15

请看下面的代码。

trait MyTrait { val myVal : String }

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

class MyClass2(val myVal: String) extends MyTrait 

为什么在MyClass和的情况下初始化顺序不同MyClass2MyClasswill的构造函数为

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 包括对语句序列 stats 的评估。如果这不是一个特征的模板,那么它的评估包括以下步骤。

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

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

对构造函数调用xc 目标的评估。. .(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 回答