[英]Scala initialization behaviour
请查看以下代码。
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
}
MyClass2
的构造MyClass2
将是
MyClass2(String myVal) { this.myVal = myVal; MyTrait$class.$init$(this) }
我认为初始化顺序应该是MyClass2
的构造函数,两种情况都是一样的。
在Scala规范的 5.1节末尾,定义了以下内容:
模板评估。 考虑 MT 1亿吨N {}统计模板SC。 如果这是特征的模板(第5.3.3节),那么它的mixin评估包括对语句序列统计的评估。 如果这不是特征的模板,则其评估包括以下步骤。
- 首先,评估超类构造函数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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.