【问题标题】:Scala: Trait initialisation code using hard-coded valuesScala:使用硬编码值的特征初始化代码
【发布时间】:2018-02-23 15:39:52
【问题描述】:

以下代码:

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 = O1", "...s = O1"
  • "...s = A ", "...s = O1"

但都没有发生。

s 留下一个抽象的val 而不是def 时,我可以理解类似的行为,但我觉得很奇怪这个值被简单地忽略了。我的问题是:

  • 导致这种行为的表面原因是什么?
  • 编译器看到在具有硬编码值的特征与具有抽象值的特征中运行初始化块的情况有多么相似/不同。
  • 为什么 Scala 决定这样做,而不是上面详述的两个预期场景。
  • 编译器不应该警告我们在特征体中除了值设置以外的任何内容?

【问题讨论】:

    标签: scala oop inheritance overriding traits


    【解决方案1】:

    这是由于s子类 覆盖Scala compiler 会将其转换为抽象val,例如:

    public abstract java.lang.String s();
    

    s 将在所有superclass 完成初始化(A) 后初始化,它只会在superclass 完成初始化后初始化一次(在O1O2),所以当A的初始化块正在尝试打印s 将得到null

    并且有一个参考是有帮助的:

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

    【讨论】:

      猜你喜欢
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 1970-01-01
      • 1970-01-01
      • 2014-09-14
      • 2011-12-19
      相关资源
      最近更新 更多