什么时候在 Scala 中初始化惰性值?换句话说,以下代码是否从将变量声明为惰性中获得了一些好处?
lazy val xOption = table.get(x)
lazy val yOption = table.get(y)
lazy val xyOption = table.get(x + y)
(xOption, yOption, xyOption) match { ... }
运算符(方法)是否match
初始化所有三个变量?
什么时候在 Scala 中初始化惰性值?换句话说,以下代码是否从将变量声明为惰性中获得了一些好处?
lazy val xOption = table.get(x)
lazy val yOption = table.get(y)
lazy val xyOption = table.get(x + y)
(xOption, yOption, xyOption) match { ... }
运算符(方法)是否match
初始化所有三个变量?
你可以在这里删除match
:
(xOption, yOption, xyOption)
此表达式创建Tuple3
. 没有语法糖:
Tuple3.apply(xOption, yOption, xyOption)
apply
方法声明:
def apply[T1, T2, T3](_1: T1, _2: T2, _3: T3): (T1, T2, T3)
所有参数都是call-by-value
,因此在apply
方法评估之前评估参数值。
Withcall-by-name
参数lazy val
将不会被评估。
match
调用unapply
方法,因此评估取决于unapply
方法实现:
lazy val a = { println("a"); 1 }
lazy val b = { println("b"); 1 }
lazy val c = { println("c"); 1 }
scala> val s = a #:: b #:: c #:: Stream.empty
a
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> s match {
| case x #:: _ => x
| }
b
res0: Int = 1
如您所见c
,未评估,a
在Stream
创建时b
评估并在#::.unapply
方法中评估。
来自Scala 规范:
惰性修饰符适用于值定义。
惰性值在第一次被访问时被初始化(这可能永远不会发生)。在初始化期间尝试访问惰性值可能会导致循环行为。如果在初始化期间抛出异常,则认为该值未初始化,稍后访问将重试评估其右侧。
简单地说,它会在你第一次使用时初始化。在您的情况下,第一次match
调用表达式。虽然那时桌子需要有x
。
如果你看到它的实现(从 Scala 2.10 开始,它在未来的版本中有所改变): 它使用著名的双重锁定成语:private volatile T result;
public T getValue() {
if (result != null) {
return result;
} else {
synchronized (this) {
if (result == null) {
result = //initialize
return result;
} else {
return result;
}
}
}
}