Scala初始化行为

Dmi*_*try 15 scala initialization traits

请查看以下代码.

trait MyTrait { val myVal : String }

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

class MyClass2(val myVal: String) extends MyTrait 
Run Code Online (Sandbox Code Playgroud)

为什么初始化顺序在MyClassMyClass2?的情况下有所不同?构造函数MyClass将为

MyClass() {
  MyTrait$class.$init$(this);
  myVal = value
}
Run Code Online (Sandbox Code Playgroud)

构造函数MyClass2将是

MyClass2(String myVal) { this.myVal = myVal; MyTrait$class.$init$(this) }
Run Code Online (Sandbox Code Playgroud)

我认为初始化顺序应该像MyClass2构造函数那样,两种情况都是一样的.

Dan*_*ral 23

Scala规范的 5.1节末尾,定义了以下内容:

模板评估.考虑一个模板SC MT 1 MT N {}的统计信息.如果这是一个特点(第5.3.3节)的模板,那么它混入评价由语句序列统计数据的评估.如果这不是特征的模板,则其评估包括以下步骤.

  • 首先,评估超类构造函数sc(第5.1.1节).
  • 然后,在模板的线性化(§5.1.2)的基类到模板的超类由SC表示被混入评估.混合评估在线性化中以相反的顺序发生.
  • 最后评估语句序列统计信息.

但请注意,构造函数参数可以由跟随它的任何构造函数使用.因此,需要在它们之前进行初始化.这在第5.1.1节末尾明确说明:

对构造函数调用xc targs的评估...(argsn)包括以下步骤:

  • 首先,评估前缀x.
  • 然后,参数args1 ,. ..,argsn从左到右进行评估.
  • 最后,通过评估c引用的类的模板来初始化正在构造的类 .

这个你没有任何问题,但你最后执行的{stats}确实有问题.最后执行{stats}的原因是它可能引用其祖先类和特征的属性,而祖先显然不知道它的后代.因此,祖先需要在{stats}执行之前完全初始化.

当然,可能你需要早期初始化.第5.1.6节:早期定义涵盖了这一点.这是你如何写它:

class MyClass extends { val myVal = "Value" } with MyTrait
Run Code Online (Sandbox Code Playgroud)