NPE在使用Scala Array.fill

Atu*_*rya 2 scala

我读的斯卡拉,第三版编程由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)

aci*_*ost 5

这里的问题是contents,当您定义时,构造函数中仍未定义line。如果line是a val,则它不选择被覆盖的width,而是使用抽象的,而后者又使用contents,但仍未定义,您将获得NPE。您可以通过查看stacktrace并注意到width抽象类中的定义抛出NPE来看到此情况。

line被定义为方法时,它不会执行,直到您调用它为止,届时内容将被完全定义,因为它可以调用line将被完全定义的(另一个方法)。

底线:和之间有一种“ 循环依赖 ” 。linecontents