В 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.
}

Кроме того, вы можете четко видеть, когда это значение оценивается.

В любом случае, если вы так уверены, что делаете, вы можете использовать любой из них. Решение за вами.

Другие вопросы по тегам