2016-05-27 33 views
5

我學習ScalaProgramming in Scala 3rd EdCh 10, Page 225,部分Overriding methods and fields,它說斯卡拉與VAL覆蓋高清,拋出NPE

的統一訪問原則僅僅是一個方面的基礎斯卡拉對待 字段和方法更均勻地比Java 。另一個區別是在Scala中, ,字段和方法屬於同一個命名空間。這個 使字段可以覆蓋無參數的方法。對於 例如,你可以 ArrayElement從一個字段的方法改變內容的執行類,而無需修改的類元素含量 抽象方法定義,如 清單10.4:

我基於示例代碼

與高清

abstract class Element { 
    def contents: Array[String] 

    val height = contents.length 

    val width = if (height == 0) 0 else contents(0).length 
} 


class ArrayElement(contnts: Array[String]) extends Element { 
    def contents: Array[String] = contnts 
} 

// -- 
val ae = new ArrayElement(Array("hello", "world")) 
ae.height 
ae.width 

我得到

ae: ArrayElement = [email protected] 
res0: Int = 2 
res1: Int = 5 

與高清重寫爲VAL在ArrayElement

abstract class Element { 
    def contents: Array[String] 

    val height = contents.length 

    val width = if (height == 0) 0 else contents(0).length 
} 


class ArrayElement(contnts: Array[String]) extends Element { 
    val contents: Array[String] = contnts 
} 

// -- 
val ae = new ArrayElement(Array("hello", "world")) 
ae.height 
ae.width 

我得到NPE作爲

java.lang.NullPointerException 
    at #worksheet#.Element.<init>(scratch.scala:4) 
    at #worksheet#.ArrayElement.<init>(scratch.scala:10) 
    at #worksheet#.ae$lzycompute(scratch.scala:15) 
    at #worksheet#.ae(scratch.scala:15) 
    at #worksheet#.#worksheet#(scratch.scala:14) 

我缺少什麼?

回答

7

級別字段在任何其他之前被初始化,這意味着null被分配。您可以使聲明爲lazy val,並且在被調用之前它不會被初始化。這是def工作的原因。一種更好的方式,雖然,而不是創建一個類的公共領域陰影的私有構造領域,是剛剛做出的構造領域的公衆這樣的:

class ArrayElement(val contnts: Array[String]) extends Element {} 

因爲有一個在這裏打球父類也是如此,這將是很好將其標記爲壓倒性的;

class ArrayElement(override val contnts: Array[String]) extends Element {} 

如果這將是一個無狀態的數據容器類,但是,最好的選擇是讓一個case class,其中(除其他幾件事情)具有公共的默認領域。

case class ArrayElement(override val contnts: Array[String]) extends Element 

這是更爲慣用的Scala,它會爲您提供價值爲基礎equalshashCode,模式匹配,結構更簡單(無需new

+1

真。一個簡單的經驗法則是從不在'val'內引用一個抽象的'def',因爲沒有保證'val'在val被實例化的時候會有任何值。 @Daenyth,我編輯了你的評論以提供另一種選擇 – Sergey