使用来自 Scala case 对象的超类的 require 子句

Using a superclass' require clause from a Scala case object

我有下面的 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

对我来说,这表明超类 require 在 case 对象中的参数覆盖发生之前被调用,但不知何故编译器 "knows" 会发生覆盖,并且它需要参数数据类型的默认值,在本例中为零。

为什么会这样,当对象中的参数被覆盖时,如何使用超类的参数化 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
}

另一种方法是在覆盖时使用 "early definition" 语法。 abstract class 代码未更改,但 object 看起来像这样。

case object O extends {
  override protected val min: Int = 3
  override protected val max: Int = 5
} with C(3)

第三种选择是使用 "constant value definitions",但这往往更麻烦且不太方便。

有关所有三个选项的详细信息,请访问 this FAQ