Scala:为什么我要将by-name参数保存为Function0

时间:2016-07-14 07:50:07

标签: scala pass-by-name

我正在研究Signal的一个示例,并且无法理解这种语法,

class Signal[T](expr: => T) {
 import Signal._
 private var myExpr: () => T = _
 private var myValue: T = _
 private var observers: Set[Signal[_]] = Set()
 private var observed: List[Signal[_]] = Nil
 update(expr)

更新方法写为

    protected def update(expr: => T): Unit = {
    myExpr = () => expr
    computeValue()
  }

我可以理解expr正在通过名称传递,因此仅在被调用时进行评估。 但我无法理解的是myExpr为什么表示为() => T? 同样为什么作业被写为myExpr = () => expr。据我所知() => expr表示返回expr的Function0。 我认为我对byname的理解是错误的。有人可以详细说明一下吗?

或者我们可以按如下方式重写上述语法,

  class Signal[T](expr: () => T) {
  import Signal._
  private var myExpr: () => T = _
  private var myValue: T = _
  private var observers: Set[Signal[_]] = Set()
  private var observed: List[Signal[_]] = Nil
  update(expr)

更新方法为,

 protected def update(expr: () => T): Unit = {
    myExpr = expr
    computeValue()
  }

1 个答案:

答案 0 :(得分:2)

expr: => T

因为函数参数代表 call-by-name ,它不仅是延迟评估(也称为懒惰),而且每次访问时都会对其进行评估。

private var myExpr: () => T = _

表示它是() => T类型的变量,这意味着它不接受任何参数并返回T。如果你将expr: () => T作为函数参数,它会创建一个() => T类型的参数,这再次表示它不接受任何参数并返回T,这不是 call-by-名称的。 由于语法的相似性,这两件事情略有混淆,但却完全不同。

您可以像这样使用它:

myExpr = () => 4
myExpr() //evaluates as 4

调用myExpr()而不指定() => 4会导致java.lang.NullPointerException

在课程中,Odersky用他的def loop: Unit = loop示例非常清楚地解释了什么是按姓名调用评估。