Var,Val 和 Def
由於 val 在語義上是靜態的,因此無論它們出現在程式碼中,它們都會就地初始化。當在抽象類和特徵中使用時,這會產生令人驚訝和不良行為。
例如,假設我們想製作一個名為 PlusOne 的特徵,它定義了一個包裝的 Int 的增量操作。由於 Ints 是不可變的,所以在初始化時已知值加 1,之後永遠不會改變,因此在語義上它是一個 val。但是,以這種方式定義它將產生意想不到的結果。
trait PlusOne {
val i:Int
val incr = i + 1
}
class IntWrapper(val i: Int) extends PlusOne
無論你使用什麼價值 i,在返回的物件上呼叫 .incr 將始終返回 1.這是因為 val incr 在特徵中初始化,在擴充套件類之前,並且此時 i 僅具有預設值 0 。 (在其他情況下,它可能會填充 Nil,null 或類似的預設值。)
因此,一般規則是避免在依賴於抽象欄位的任何值上使用 val。相反,使用 lazy val,它在需要時不進行評估,或使用 def,每次呼叫時都會進行評估。但請注意,如果在初始化完成之前 lazy val 強制要求 lazy val 進行評估,則會發生相同的錯誤。