3

私は、scala での初期化順序の問題を回避するために Lazy val を一般的に使用することは理解していますが、この説明についてはいつも何かに悩まされてきました。「Lazy Val」が最初のアクセス中に初期化され、親コンストラクターが存在する可能性がある前にそれを使用している場合、ここで正確に何が起こっているのでしょうか? 以下の例では、"println("A: " + x1)" が呼び出されると、クラス B はまだ存在しませんが、値は正しく出力されます。「A: Hello」が表示されたまさにその瞬間に、これは A のコンストラクターで発生したのでしょうか、それとも B が完全に存在するまで何らかの形で遅延したのでしょうか? ある意味では、それを「レイジー」とマークすることは、直感に反して予定より早く利用できるようにしましたか?

ありがとうございました

( https://github.com/paulp/scala-faq/wiki/Initialization-Orderから参照)

abstract class A {
  val x1: String

  println("A: " + x1)
}
class B extends A {
  lazy val x1: String = "hello"    

}
4

2 に答える 2

2

オブジェクト自体は存在しませんが、オブジェクト内のフィールドが存在し、計算できます。

何が起こっているかというと、A のコンストラクター内から x1 にアクセスしているため、遅延値が強制的に計算されます。A が B の x1 メソッドを呼び出す必要があることを知ることができる理由は、(Java と同様に) 動的にディスパッチされるためです。

それが役立つ場合、スタックは次のようになります。

B.x1$lzycompute
B.x1
A.<init>
B.<init>

それが役立つ場合は、Java でのコードの大まかなバージョンを次に示します。

public class Testing {

    public static void main(String[] args) {
        new B();
    }

    public static abstract class A {

        public abstract String x1();

        public A() {
            System.out.println(x1());
        }
    }

    public static class B extends A {
        private boolean inited = false;
        private String x1;

        private String computeX1() {
            x1 = "hello";
            inited = true;
            return x1;
        }

        public String x1() {
            return this.inited ? x1 : computeX1();
        }
    }

}
于 2013-08-12T03:45:37.243 に答える