2012-12-17 26 views
1

對此的答案是:對於scala中的對象是不可變的?

對象的實例化使用'val'而不是'var'。

正在創建的對象的每個成員變量也是'val'而不是'var'。這是爲了防止用戶在設置後更新對象值。

+0

維基百科[似乎同意你](http://en.wikipedia.org/wiki/Immutable_object#Scala)。 –

+4

@RobertHarvey然後維基百科是錯誤的。如果一個對象被一個'val'引用,並且它的所有成員都是'val's,如果它的成員是可變的,它仍然可以是可變的。即使被「var」引用,一個不可變對象也是不可變的。 – sepp2k

+1

@ sepp2k:在你回答這個問題之後,你是否會修好維基百科條目以及如此好? :) –

回答

7

如果對象的用戶沒有辦法讓它變異,則對象是不可變的。這意味着它不必重新分配其任何成員變量或改變這些變量引用的任何對象。如果所有對象的成員都是val,這確保前者(即它們不能被重新分配),而不是後者(即,如果由這些變量引用的對象本身是可變的,則它們仍然可以通過調用變異方法即使他們僅被val s引用)。

還要注意的是,即使成員被聲明爲var S,對象仍然是不可變的,如果沒有一個對象的方法實際上是重新分配變量(或叫突變它們的方法) - 假設的過程中,它們是私有的。

因此只有val成員對於一個對象是不可變的既不必要也不足夠。無論對象是由val還是var(或兩者)引用都沒有什麼區別。

1

@ sepp2k很好地正確地解釋了一個對象的標準是在技術上不可變。他的答案中遺漏的一個微妙之處是並非所有成員變量都對應於外部可見的狀態。成員也可以是例如一個緩存的內部值,用於存儲一些本地難以計算的數據,這些數據不能從外部直接看到(因此在Scala中被限定爲private[this])。一個對象可以有這樣的一個成員,例如存儲計算出的散列值。它甚至可以通過公共getter訪問 - 只要訪問器的行爲是純粹的功能,即它總是爲同一對象上的每次調用產生相同的值(除了在重用內部緩存值時它的返回速度更快)。

Scala編譯器知道這個區別,所以它可以幫助你正確地實現一個不可變類,即使在內部使用可變狀態。當泛型類型變化發揮作用時,這很重要。也就是說,即使類包含這種類型的可重新分配字段,編譯器也允許泛型類型參數協變 - 只要這些字段是private[this],確保不能引用包含比靜態類型更弱的類型的對象類型的對象被定義爲(這將是導致類型錯誤的方差的前提條件)。

這將在Programming in Scala的第19.7節中詳細說明,代碼示例如下。

相關問題