这是 Scala 构造 val 成员的方式的一个不幸问题。
trait Rectangular {
def width: Int
def height: Int
val area = width * height
}
case class Square(val size: Int) extends Rectangular {
val width = size
val height = size
}
在这里,Scala 在内部将Square 中的私有成员称为width 和height。它将它们初始化为零。然后,在Square 构造函数中,设置它们。基本上,它做的事情与这段 Java 代码很接近。
public abstract class Rectangular {
private int area;
public Rectangular() {
area = width() * height();
}
public abstract int width();
public abstract int height();
public int area() { return area; }
}
public class Square extends Rectangular {
private int width, height;
public Square(int size) {
Rectangular();
width = size;
height = size;
}
public int width() { return width; }
public int height() { return width; }
}
请注意,Rectangular 构造函数在 Square 构造函数之前调用,因此 area 在设置之前会看到默认的零 width 和 height 值。正如您已经发现的那样,使用lazy val 可以解决问题。
trait Rectangular {
def width: Int
def height: Int
val area = width * height
}
case class Square(val size: Int) extends Rectangular {
lazy val width = size
lazy val height = size
}
或者,您可以使用早期初始化语法来强制以正确的顺序写入值。
trait Rectangular {
def width: Int
def height: Int
val area = width * height
}
case class Square(val size: Int) extends {
val width = size
val height = size
} with Rectangular
lazy val 解决方案通常更可取,因为它可以减少未来的意外。
有关详细信息,请参阅有关此特定主题的Scala FAQ。