我有下面的 Scala 代码,我想在其中使用来自 case 对象的超类require
子句,其中 require
中使用的参数被覆盖:
sealed abstract class C(val i: Int) {
protected val min: Int = 1
protected val max: Int = 5
require(i >= min && i <= max,
s"$i should be between $min and $max, inclusive")
}
case object O extends C(3) {
override protected val min: Int = 3
override protected val max: Int = 5
}
println(O)
但是,打印O
给了我java.lang.IllegalArgumentException: requirement failed: 3 should be between 0 and 0, inclusive
例外。
仅覆盖其中一个参数:
case object O extends C(3) {
override protected val max: Int = 5
}
导致异常java.lang.IllegalArgumentException: requirement failed: 3 should be between 1 and 0, inclusive
。
对我来说,这表明在 case 对象中的参数被覆盖之前调用了超类的require
,但不知何故编译器"知道"将会发生覆盖,并且它采用参数数据类型的默认值,在本例中为零。
为什么会这样,当对象中的参数被覆盖时,如何使用 case 对象中的超类参数化require
子句?
你对执行和初始化顺序的假设是正确的。
要解决此问题,您有几种不同的选择。一种是使每个val
都被覆盖为lazy val
,如下所示:
sealed abstract class C(val i: Int) {
protected lazy val min: Int = 1
protected lazy val max: Int = 5
require(i >= min && i <= max,
s"$i should be between $min and $max, inclusive")
}
case object O extends C(3) {
override protected lazy val min: Int = 3
override protected lazy val max: Int = 5
}
另一种方法是在重写时使用"早期定义"语法。abstract class
代码保持不变,但object
如下所示。
case object O extends {
override protected val min: Int = 3
override protected val max: Int = 5
} with C(3)
第三种选择是使用"常量值定义",但这往往更麻烦且不太方便。
有关所有三个选项的详细信息,请参阅此常见问题解答。