0

什么时候在 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初始化所有三个变量?

4

3 回答 3

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方法评估之前评估参数值。

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,未评估,aStream创建时b评估并在#::.unapply方法中评估。

于 2013-08-21T06:10:06.137 回答
1

来自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;
                }
            }
        }
    }
于 2013-08-21T06:07:37.453 回答
-1

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

所以是的,如果您的 patMat 构造是您访问 vals 的第一个地方,它将生成一个由三个元素组成的元组,其中包含 vals 值。

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

于 2013-08-21T06:06:20.760 回答