15

次のコードを見てください。

trait MyTrait { val myVal : String }

class MyClass extends MyTrait { val myVal = "Value" }

class MyClass2(val myVal: String) extends MyTrait 

MyClassとの場合で初期化順序が異なるのはなぜMyClass2ですか? のコンストラクタは次のMyClassようになります

MyClass() {
  MyTrait$class.$init$(this);
  myVal = value
}

MyClass2willのコンストラクタは

MyClass2(String myVal) { this.myVal = myVal; MyTrait$class.$init$(this) }

MyClass2初期化の順序は、コンストラクターと同じようにする必要があると思います。どちらの場合も同じです。

4

1 に答える 1

23

Scala 仕様のセクション 5.1 の最後に、次のように定義されています。

テンプレートの評価。mt 1mt n {stats}を持つテンプレートsc考えてみましょう。これが特性 (§5.3.3) のテンプレートである場合、その mixin-evaluation は、ステートメント シーケンス統計の評価で構成されます。これが特性のテンプレートでない場合、その評価は次の手順で構成されます。

  • 最初に、スーパークラス コンストラクター sc が評価されます (§5.1.1)。
  • 次に、sc で示されるテンプレートのスーパークラスまでの、テンプレートの線形化 (§5.1.2) のすべての基本クラスが mixin 評価されます。Mixin 評価は、線形化で発生した順序とは逆の順序で発生します。
  • 最後に、ステートメント シーケンスの統計が評価されます。

ただし、コンストラクターのパラメーターは、それに続く任意のコンストラクターによって使用される可能性があることに注意してください。したがって、それらの前に初期化する必要があります。これは、セクション 5.1.1 の最後に明示されています。

コンストラクター呼び出しxc targs の評価。. .(argsn)は、次の手順で構成されます。

  • 最初に、プレフィックスxが評価されます。
  • 次に、引数args1 、 . . . 、argsnは左から右に評価されます。
  • 最後に、構築されるクラスは、 cによって参照されるクラスのテンプレートを評価することによって初期化され ます。

これには問題はありませんが、最後に実行される{stats}に問題があります。{stats}が最後に実行される理由は、祖先のクラスと特性の属性を参照する可能性があるためです。一方、祖先は明らかにその子孫についての知識を持っていません。したがって、 {stats}が実行される前に祖先を完全に初期化する必要があります。

もちろん、早期の初期化が必要になる可能性はあります。これは、セクション 5.1.6: 初期の定義でカバーされています。書き方は次のとおりです。

class MyClass extends { val myVal = "Value" } with MyTrait
于 2010-09-30T14:08:12.350 に答える