抽象超类 Scala 中的断言创建 NPE

Assertions in abstract superclass scala creating NPE

以下代码,在REPL中输入时

abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }

class B extends A { val aSet = Set(4,5,6) }

new B()

给出空点异常,而不是不变的失败。

解决这个问题的最佳成语是什么?


类似问题:

还有在线评论:https://gist.github.com/jkpl/4932e8730c1810261381851b13dfd29d

当您声明 val 时,会发生几件事:

  1. 编译器确保在 class 的实例初始化时为变量分配足够的 space
  2. 访问器方法已创建
  3. 设置变量初始值的初始化程序已创建。

您的代码

abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }
class B extends A { val aSet = Set(4,5,6) }
new B()

大致相当于

abstract class A { 
  private var aSet_A: Set[Int] = null
  def aSet: Set[Int] = aSet_A
  require(aSet.contains(3)) 
}

class B extends A {
  private var aSet_B: Set[Int] = Set(4,5,6) 
  override def aSet: Set[Int] = aSet_B
}

new B()

因此,会发生以下情况:

  1. aSet_AaSet_B 的内存已分配并设置为 null
  2. A 的初始化器是 运行。
  3. require on aSet.contains(3) 被调用
  4. 由于 aSetB 中被覆盖,它 returns aSet_B.
  5. 由于 aSet_Bnull,因此抛出 NPE。

为避免这种情况,您可以将 aSet 实现为惰性变量:

abstract class A { 
  def aSet: Set[Int]
  require(aSet.contains(3)) 
}

class B extends A {
  lazy val aSet = Set(4,5,6) 
}

new B()

这会引发 requirement failed 异常:

java.lang.IllegalArgumentException: requirement failed

必须 link Scala 的常见问题解答:

相关问题列表: