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

时间:2018-02-23 15:39:52

标签: scala oop inheritance override traits

以下代码:

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决定这样做,而不是上面详述的两个预期方案。
  • 编译器是否应该警告我们除了特征体中的值设置之外还有什么?

1 个答案:

答案 0 :(得分:2)

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

public abstract java.lang.String s();

s将在所有superclass完成初始化(A)后初始化,并且只会在O1O2之后初始化一次superclassA {1}}已完成初始化,因此当s的初始化块尝试打印null时,将获得Query 1 ------ select value from bindings where id in (31213,31199) This query returns Answer ----------------------- TeamA Query 2 ------- SELECT LTRIM(RTRIM(Number)) FROM OPENJSON('{"value":"6","text":"Apiutharun"}', '$' ) WITH ([Number] NVARCHAR(100) '$.value') This query returns Answer ------------------------ 6

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

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