如何在 subtrait 中初始化 trait 的 vals?
How to initialize trait's vals in subtrait?
我尝试在特征中使用抽象 val
来初始化另一个值。我得到了 NullPointerException
。我将行为归结为最小的测试用例:
trait MessagePrinter {
val message: String
println(message)
}
class HelloPrinter extends MessagePrinter {
val message = "Hello World"
}
val obj = new HelloPrinter()
println(obj.message)
这个小程序产生以下结果:
null
Hello World
我的印象是 val 可能永远不会改变。这是预期的行为还是编译器错误?如何解决此问题并在初始化期间打印 Hello World
?
你应该在这两种情况下使用 def
。
描述此行为的来源之一是“Scala Puzzlers”Puzzler 4:
The following rules control the initialization and overriding behavior
of vals:
- Superclasses are fully initialized before subclasses.
- Members are initialized in the order they are declared.
- When a val is overridden, it can still only be initialized once.
- Like an abstract val, an overridden val will have a default initial value during the construction of superclasses.
在Scala specification的5.1节中,super类首先被初始化。尽管 vals
通常无法重新实例化,但它们在构造期间确实以默认初始值开始。您可以使用具有不同语义的 def
:
trait MessagePrinter {
def message: String
println(message)
}
class HelloPrinter extends MessagePrinter {
def message = "Hello World"
}
或者您可以考虑像这样切换:
class HelloPrinter extends { val message = "Hello World" } with MessagePrinter
在这种情况下,超级 类 会按顺序进行评估,因此 MessagePrinter
初始化应该按预期工作。
我尝试在特征中使用抽象 val
来初始化另一个值。我得到了 NullPointerException
。我将行为归结为最小的测试用例:
trait MessagePrinter {
val message: String
println(message)
}
class HelloPrinter extends MessagePrinter {
val message = "Hello World"
}
val obj = new HelloPrinter()
println(obj.message)
这个小程序产生以下结果:
null
Hello World
我的印象是 val 可能永远不会改变。这是预期的行为还是编译器错误?如何解决此问题并在初始化期间打印 Hello World
?
你应该在这两种情况下使用 def
。
描述此行为的来源之一是“Scala Puzzlers”Puzzler 4:
The following rules control the initialization and overriding behavior of vals:
- Superclasses are fully initialized before subclasses.
- Members are initialized in the order they are declared.
- When a val is overridden, it can still only be initialized once.
- Like an abstract val, an overridden val will have a default initial value during the construction of superclasses.
在Scala specification的5.1节中,super类首先被初始化。尽管 vals
通常无法重新实例化,但它们在构造期间确实以默认初始值开始。您可以使用具有不同语义的 def
:
trait MessagePrinter {
def message: String
println(message)
}
class HelloPrinter extends MessagePrinter {
def message = "Hello World"
}
或者您可以考虑像这样切换:
class HelloPrinter extends { val message = "Hello World" } with MessagePrinter
在这种情况下,超级 类 会按顺序进行评估,因此 MessagePrinter
初始化应该按预期工作。