在REPL中输入以下代码
abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }
class B extends A { val aSet = Set(4,5,6) }
new B()
给出空值异常,而不是不变的失败。
解决这个问题的最佳习惯是什么?
类似的问题:
Code Contracts: Invariants in abstract class
Private constructor in abstract class Scala?
以及在线评论:https://gist.github.com/jkpl/4932e8730c1810261381851b13dfd29d
答案 0 :(得分:2)
当您声明val
时,会发生几件事:
您的代码
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()
因此,会发生以下情况:
aSet_A
和aSet_B
的内存并将其设置为null
。A
的初始化程序已运行。require
上的aSet.contains(3)
aSet
中的B
被覆盖,因此它返回aSet_B
。aSet_B
是null
,因此会引发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
Scala FAQ的必填链接:
相关问题列表: