什么时候lazy val被初始化了?

时间:2013-08-21 05:53:16

标签: scala lazy-evaluation

什么时候在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运算符(方法)是否初始化所有三个变量?

3 个答案:

答案 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)

来自Scala specification

  

懒惰的修改器适用于价值定义。

     

懒惰值在第一次被访问时被初始化(可能是这样   从来没有发生过)。试图在其期间访问惰性值   初始化可能会导致循环行为。如果是例外   在初始化期间抛出,该值被视为未初始化,   稍后访问将重试评估其右侧。

简单地说,它将在您第一次使用时初始化。在您的情况下,第一次调用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)

Lazy vals在第一次访问它们时初始化,它在访问后计算,然后从api的角度来看变成一个简单的val(some关于实现的注释,this SIP获取更多信息)。

所以是的,如果你的patMat构造是你访问你的vals的第一个地方,它会产生一个带有vals值的三个元素的元组。

并且match 不是方法或操作符,它是语言级别的构造。

相关问题