Scala:使用硬编码值的特征初始化代码

Scala: Trait initialisation code using hard-coded values

以下代码:

trait A{
  val s: String = "A"
  println(s"A's initialiser run, s= $s")
}

object O1 extends A {
  override val s = "O1"
  println(s"Object's initialiser run, s= $s")

  def foo: Unit = println("I am just being called to instantiate the object! :| ")
}

object O2 extends AnyRef with A {
  override val s = "O2"
  println(s"Object's initialiser run, s= $s")

  def foo: Unit = println("I am just being called to instantiate the object! :| ")
}

println("////with inheritance:")
O1.foo
println("////with mix-in:")
O2.foo

打印:

////with inheritance:
A's initialiser run, s= null
Object's initialiser run, s= O1
I am just being called to instantiate the object! :| 
////with mix-in:
A's initialiser run, s= null
Object's initialiser run, s= O2
I am just being called to instantiate the object! :| 

我觉得这种行为很奇怪。我会预料到以下行为之一:

但两者都没有发生。

s 保留为抽象 val 而不是 def 时,我可以理解类似的行为,但我发现该值被简单地忽略很奇怪。我的问题是:

这是由于s子类Scala[=35=覆盖造成的] compiler 会将其翻译成 抽象值 ,例如:

public abstract java.lang.String s();

s将在所有superclass完成初始化(A)后初始化,并且只会初始化一次(在O1O2superclass 完成初始化后,因此当 A 的初始化块尝试打印时 s 将得到 null.

并且有一个参考很有帮助:

https://docs.scala-lang.org/tutorials/FAQ/initialization-order.html