在Scala中,何时使用惰性求值参数比使用函数作为参数更好呢?

5
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个回答

5
您的观察是正确的。事实上,lazyHelloanoyHello是相同的,这是因为para: => Stringpara: () => String的速记形式。
另一种看待这个问题的方式是:() => String是一个不带参数并返回一个字符串的函数。=> String是一些在不需要参数的情况下求值为字符串的内容。因此,本质上,按名称调用是一个没有输入参数的函数。

3
基本上,惰性求值参数和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.
}

此外,您可以清楚地看到该值何时被评估。

无论如何,如果您确信自己在做什么,可以使用其中任何一个。决定权在你手中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接