什么时候在Scala lazy val初始化?换句话说,以下代码将变量声明为惰性有一些好处吗?
lazy val xOption = table.get(x)
lazy val yOption = table.get(y)
lazy val xyOption = table.get(x + y)
(xOption, yOption, xyOption) match { ... }
match
运算符(方法)是否初始化所有三个变量?
答案 0 :(得分:5)
您可以在此处删除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
方法评估之前评估参数值。
call-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
方法中进行评估。
答案 1 :(得分:1)
懒惰的修改器适用于价值定义。
懒惰值在第一次被访问时被初始化(可能是这样 从来没有发生过)。试图在其期间访问惰性值 初始化可能会导致循环行为。如果是例外 在初始化期间抛出,该值被视为未初始化, 稍后访问将重试评估其右侧。
简单地说,它将在您第一次使用时初始化。在您的情况下,第一次调用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;
}
}
}
}
答案 2 :(得分:-1)