0

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 つの変数すべてを初期化しますか?

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

ご覧のとおりcaは評価されず、Stream作成時に評価され、メソッドbで評価されます。#::.unapply

于 2013-08-21T06:10:06.137 に答える
1

Scala仕様から:

遅延修飾子は、値の定義に適用されます。

遅延値は、最初にアクセスされたときに初期化されます (まったく発生しない可能性があります)。初期化中に遅延値にアクセスしようとすると、ループ動作が発生する可能性があります。初期化中に例外がスローされた場合、値は初期化されていないと見なされ、その後のアクセスで右辺の評価が再試行されます。

簡単に言えば、最初に使用するときに初期化されます。あなたの場合、初めてmatch式が呼び出されます。それまでにテーブルが必要ですがx

その実装 (Scala 2.10 の時点で、将来のバージョンでは変更されます) が表示された場合: 有名な Double Locking Idiom を使用しています:

    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 val は最初のアクセス時に初期化され、アクセス後に計算され、API の観点から単純な val になります (実装に関するいくつかのメモ、および追加情報についてはこのSIP )。

したがって、patMat コンストラクトが vals にアクセスする最初の場所である場合、vals 値を持つ 3 つの要素のタプルが作成されます。

また、match メソッドや演算子ではなく、言語レベルの構成要素です。

于 2013-08-21T06:06:20.760 に答える