我有以下情况:
class A {
val text = "Test"
//some initialization things using text. here represented by println
println(text)
}
现在我想为该类编写单元测试,因此为此目的更改text
的值。
trait Test extends A {
override val text = "Hello"
}
class B extends A with Test
现在的问题是,如果我创建B
的实例,则文本的值按预期设置为"Hello"
,但A
中的所有初始化步骤都会得到null
的值1}} text
我的问题是为什么变量null
为原始class A
中的语句?我觉得拥有旧值似乎比没有突然没有价值更合乎逻辑。
答案 0 :(得分:4)
编写val text = ...
时,编译器会生成一个私有final字段(让我们称之为_text
)和一种访问它的方法。 A
和B
都会发生这种情况。 B
的构造函数首先调用A
的构造函数,但它使用的text
方法是B
;所以它访问B._text
,它尚未初始化!
作为@ DennisTraub答案中def
的替代方法,您还可以使用lazy val
来避免重新计算答案(def
在这种情况下更好)。在我看来,你通常不应该覆盖val
以避免这样的问题。
答案 1 :(得分:2)
不幸的是我不知道它为什么会这样,但是我使用def
代替val
解决了手头的问题:
class A {
def text = "Test"
println(text)
}
trait Mix extends A {
override def text = "Hello"
}