В Scala, когда будет подходящее время использовать лениво оцененный параметр, а не использовать функцию в качестве параметра?
def getStr(): String = {
println("getStr is running")
"str"
}
def lazyHello(para: => String) = {
println("lazy hello is runing")
println(para)
}
def notLazyHello(para: String) = {
println("not lazy hello is runing")
println(para)
}
def anoyHello(para: () => String) = {
println("anoy hello is runing")
println(para())
}
notLazyHello(getStr)
lazyHello(getStr)
anoyHello(getStr)
получил этот результат:
scala> notLazyHello(getStr)
getStr is running
not lazy hello is runing
str
scala> lazyHello(getStr)
lazy hello is runing
getStr is running
str
scala> anoyHello(getStr)
anoy hello is runing
getStr is running
str
кажется, что lazyHello и anoyHello выполняют то же самое.
Итак, когда в Scala было бы лучше использовать лениво оцененный параметр, а не использовать функцию в качестве параметра?
2 ответа
Ваше наблюдение верно. lazyHello
а также anoyHello
на самом деле то же самое. Это потому что para: => String
это сокращение для para: () => String
,
Еще один способ взглянуть на это:
() => String
это функция, которая не принимает параметров и возвращает строку
=> String
это то, что вычисляется в строку, без принятия параметров. По сути, вызов по имени - это функция без входного параметра.
По сути, нет технической разницы между ленивым оцениваемым параметром и Function0
параметр. Есть плюсы и минусы как реализации.
Function0
параметр определенно многословен. Так что если вы измените их на ленивый параметр, код станет более читабельным.
Вот склонная к ошибкам ситуация ленивых вычислений.
Рассмотрим следующий код
def inner = println("inner called")
def execute(f: => Unit) = {
println("executing")
f
}
def redirect(f: => Unit) = {
println("redirecting")
execute(f)
}
redirect(inner) // will print -
// redirecting
// executing
// inner called
Теперь подумайте, почему-то забыли поставить =>
в функции выполнения. Код будет компилироваться правильно, но поведение будет другим и может привести к ошибкам.
def execute(f: Unit) = {
println("executing")
f
}
def redirect(f: => Unit) = {
println("redirecting")
execute(f)
}
redirect(inner) // will print -
// redirecting
// inner called
// executing
Но если вы используете Function0
код не скомпилируется. Итак Function0
параметры менее подвержены ошибкам.
def inner() = println("inner called")
def execute(f:() => Unit) = {
println("executing")
f()
}
def redirect(f:() => Unit) = {
println("redirecting")
execute(f)
}
redirect(inner) // will print -
// redirecting
// executing
// inner called
=========================================
def inner() = println("inner called")
def execute(f:Unit) = {
println("executing")
f
}
def redirect(f:() => Unit) = {
println("redirecting")
execute(f) // Will not compile.
}
Кроме того, вы можете четко видеть, когда это значение оценивается.
В любом случае, если вы так уверены, что делаете, вы можете использовать любой из них. Решение за вами.