下面的代码抛出了一个 java.lang.NullPointerException
因为性状被过早地初始化了。
trait DummyTrait {
def intSeq: Seq[Int]
require(intSeq.exists(_ > 2))
}
object Dummy extends DummyTrait {
val extraIntSeq: Seq[Int] = Seq(-2,-3)
override def intSeq = Seq(1,0,4) ++ extraIntSeq
}
Dummy.intSeq
然而,下面的简单修改就解决了这个问题,但我不明白为什么。
trait DummyTrait {
def intSeq: Seq[Int]
require(intSeq.exists(_ > 2))
}
object Dummy extends DummyTrait {
lazy val extraIntSeq: Seq[Int] = Seq(-2,-3) // using `def` also works
override def intSeq = Seq(1,0,4) ++ extraIntSeq
}
Dummy.intSeq
我发现 这篇关于被覆盖的val为NULL的文档。但似乎并不适用于上面的例子,因为这个修复方法并没有涉及到在超类的接口中定义的变量。
另外,上面提出的解决方案是否是一种反模式?作为一个正在开发特质的人,我应该如何执行对抽象值的要求,而不至于让实现子类的用户感到惊讶,因为潜在的 NullPointerException
?
观察..: 我使用的是Scala 2.13.0版本。
在第一种情况下 extraIntSeq
在构造函数中被初始化 之后 超级构造函数被调用,因此NPE
object Dummy extends DummyTrait {
private[this] val extraIntSeq: Seq = _;
...
def <init>($outer: O): Dummy.type = {
Dummy.super.<init>();
Dummy.this.extraIntSeq = ... // note that it comes AFTER super
()
}
}
而在后者中,懒惰的val被转化为方法。
到目前为止,你可以使用早期的初始化器
object Dummy extends {
val extraIntSeq: Seq[Int] = Seq(-2,-3)
override val intSeq = Seq(1,0,4) ++ extraIntSeq
} with DummyTrait
https:/dotty.epfl.chdocsreferencedropped-featuresearly-initializers.html。
https:/contributors.scala-lang.orgtproposal-to-remove-early-initializers-from-the-language2144。