2017-02-18 10 views
1

私は読んでいますScalaでのプログラミング、第3版Lex Spoon著;ビル・ベナーズ; Martin Oderskyと、その途中で例を試してみましょう。NPE in scala Array.fill

例次の書籍を形成

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) 

はREPLで、またはEclipseワークシートで試してみましたjava.lang.NullPointerExceptionがを与えます。

しかし、私は

private val line = ch.toString * width 

private def line = ch.toString * width 

にエラーがobserverdされていない変更した場合。

私は理解できませんなぜ? 誰かが説明できますか?

私は@acidghostからの回答後のScala 2.11.8


編集

を使用しています、私は以下のようにクラス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) 
} 

答えて

4

問題は、あなたがlineを定義するときcontentsが、まだコンストラクタで定義されていないということです。行がvalの場合は、オーバーライドされたwidthを選択せず​​、代わりにcontentsを使用する抽象的なものを使用します。これはまだ定義されておらず、NPEを取得します。 stacktraceを見て、抽象クラスのwidthの定義によってNPEがスローされたことに注目すると、これを見ることができます。

lineがメソッドとして定義されている場合、呼び出すまで実行されず、完全に定義されるline(別のメソッド)を呼び出すことができるため、そのコンテンツは完全に定義されます。

ボトムライン:あなたはlinecontentsの間で「循環依存」のようなものを持っています。

+0

種類の意味があります。 コンストラクタparamsからオーバーライドを削除し、クラス本体に追加しました。それは間違いなく動作します。 (更新されたクラス定義の付いた質問)。 これは正しい方法だと思いますか? ありがとうございます! –

+0

はい、これは正しい方法です。 – acidghost