我正在阅读Lex Spoon的Programming in Scala,第三版(也出现在第四版中);比尔·文纳斯;马丁·奥德斯基,并在此过程中尝试示例。
本书中的以下示例 |在斯卡拉小提琴中运行
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)
给出java.lang.NullPointerException,当在REPL或Eclipse工作表中尝试时。
如果我改变
private val line = ch.toString * width
自
private def line = ch.toString * width
不会发生任何错误。
有人可以解释一下吗?
我正在使用 scala 2.11.8
这里的问题是,当您定义contents
时,line
时,构造函数中仍未定义。如果 line 是一个val
,它不会选择被覆盖的width
,而是使用抽象的,而抽象的contents
仍然没有定义,你得到 NPE。您可以通过查看堆栈跟踪并注意 NPE 是由抽象类中的width
定义引发
的。当line
被定义为方法时,它不会执行,直到你调用它,到那时内容将被完全定义,因为它可以调用将完全定义的line
(另一个方法)。
在 ScalaFiddle 上运行
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 def line: String = ch.toString * width
def contents = Array.fill(height)(line)
}
val e3: Element = new UniformElement('x', 2, 3)
底线:你在line
和contents
之间有一种">循环依赖"。