我读的斯卡拉,第三版编程,由Lex勺; Bill Venners;Martin Odersky,并尝试各种示例。
以下示例构成本书
abstract class Element {
def contents: Array[String]
val height = contents.length
val width = if (height == 0) 0 else contents(0).length
}
class UniformElement(
ch: Char,
override val width: Int,
override val height: Int
) extends Element {
private val line = ch.toString * width
def contents = Array.fill(height)(line)
}
val e: Element = new UniformElement('x', 2, 3)
Run Code Online (Sandbox Code Playgroud)
在REPL或Eclipse工作表中尝试给出java.lang.NullPointerException。
但是如果我改变
private val line = ch.toString * width
Run Code Online (Sandbox Code Playgroud)
至
private def line = ch.toString * width
Run Code Online (Sandbox Code Playgroud)
没有观察到错误。
我不明白为什么?有人可以解释一下吗?
我正在使用scala 2.11.8
编辑
从@acidghost回答后,我如下更改类UniformElement,但未获得NPE。:)
class UniformElement(
ch: Char,
val w: Int,
val h: Int
) extends Element {
override val width: Int = w
override val height: Int = h
private val line = ch.toString * width
def contents = Array.fill(height)(line)
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是contents,当您定义时,构造函数中仍未定义line。如果line是a val,则它不选择被覆盖的width,而是使用抽象的,而后者又使用contents,但仍未定义,您将获得NPE。您可以通过查看stacktrace并注意到width抽象类中的定义抛出NPE来看到此情况。
当line被定义为方法时,它不会执行,直到您调用它为止,届时内容将被完全定义,因为它可以调用line将被完全定义的(另一个方法)。
底线:和之间有一种“ 循环依赖 ” 。linecontents