2

重複の可能性:
Scala と前方参照

以下がScalaで機能する理由はありますか:

バージョン 1

object Strange extends App {
  val x = 42
  Console.println(x) // => outputs "42", as expected
}

バージョン 2

object Strange extends App {
  Console.println(x) // => "0" ?!
  val x = 42
}

なぜそれはまったくコンパイルされ、なぜ警告などなし非常に奇妙な動作をするのですか?

次の場合も同じ問題classです。

class StrangeClass {
  Console.println(x) // => still "0"
  val x = 42
}

object TestApp extends App {
  new StrangeClass()
}

通常のメソッドの本体にはそのような問題はありません:

def nonStrangeMethod {
  Console.println(y) // => fails with "not found: value y", as expected
  y = 42
}

また、val 宣言に「final」を追加すると、動作が劇的に変わります。

class StrangeClass {
  Console.println(x) // => "42", but at least that's expected
  final val x = 42
}

レコードの場合、次の Java 静的 (Scala のobject) 対応物:

public class Strange {
    static {
        System.out.println(x);
    }
    static int x = 42;

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

class#3 行目と Java の非静的 (Scala の) 対応するエラー「定義される前にフィールドを参照できません」でコンパイルに失敗します。

public class Strange {
    Strange() {
        System.out.println(x);
        int x = 42;
    }

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

明らかに、3 行目の「x を変数に解決できません」で失敗します。

4

2 に答える 2

3

Appこれは、遅延初期化を使用する特性のためです。特性 に関するScalaでのプログラミングから:App

中括弧の間のコードは、シングルトン オブジェクトのプライマリ コンストラクターに集められ、クラスの初期化時に実行されます。

2.9.0 リリースにも次のように記載されています。

App トレイトを継承するオブジェクトは、代わりに Scala 2.9 の遅延初期化機能を利用して、継承されたメイン メソッドの一部として本体全体を実行します。

したがって、これを出力として取得する場所でConsole.println(x)実行されるまで実行されません。Strange

scala> s.main(Array[String]())
0

Console.println(x)後で別のものを追加すると、次のval x = 42ように出力されます。

scala> s.main(Array[String]())
0
42

コンパイラxは が現在のスコープに存在することを認識していますが、実行されるまでその評価を遅らせてから、デフォルト値である を出力しIntます0

于 2012-11-22T02:13:29.943 に答える
2

答えは本質的に、そのコンパイラがどのように物事を構築するかです。Scala には静的変数がないため、初期化は基本的にコンストラクターで行われるため、2 番目の例に相当する Java は次のようになります。

public class Strange {
    int x = 0;

    public Strange() {
        System.out.println(x);
        x = 42;
    }
}

これは正常にコンパイルされます。NPE を回避するために、コンパイラが初期化されていない int の値を 0 に設定すると仮定します。コンストラクター内のステートメントの順序を逆にすると、最初の例で説明した動作が得られます。

この質問にはさらに詳細があります: Scala と前方参照

于 2012-11-22T02:11:53.857 に答える