2015-04-12 102 views
4

我已經知道不可變性在可變性方面的優勢,能夠推理代碼並引入更少的錯誤,特別是在多線程代碼中。儘管如此,在創建結構體時,我看不到任何好處,無法在可變結構體上創建完全不可變的結構體。不可變結構體對可變結構體的好處是什麼?

讓我們爲保持一些分數結構的一個例子:

struct ScoreKeeper { 
    var score: Int 
} 

在這種結構中,我可以改變現有的結構變量

var scoreKeeper = ScoreKeeper(score: 0) 
scoreKeeper.score += 5 
println(scoreKeeper.score) 
// prints 5 

不可改變版本將分數的值看起來像這樣:

struct ScoreKeeper { 
    let score: Int 

    func incrementScoreBy(points: Int) -> ScoreKeeper { 
     return ScoreKeeper(score: self.score + points) 
    } 
} 

及其用法:

let scoreKeeper = ScoreKeeper(score: 0) 
let newScoreKeeper = scoreKeeper.incrementScoreBy(5) 
println(newScoreKeeper.score) 
// prints 5 

我沒有看到第二種方法比第一種方法的好處,因爲結構是值類型。如果我傳遞一個結構體,它總是被複制。因此,如果結構具有可變屬性,對我來說似乎並不重要,因爲代碼的其他部分無論如何都會在單獨的副本上工作,從而消除了可變性問題。

雖然我見過一些使用第二個例子的人,但這需要更多的代碼纔沒有明顯的好處。我沒有看到一些好處嗎?

+0

當然,如果整個代碼庫中只有一個位置創建該類型的值,那麼第二個代碼只需要更多代碼? – delnan

+2

[This thread](http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil)是關於C#的,但在我看來,一些參數也適用於Swift。 –

回答

1

不同的方法將促進不同類型的代碼更改。不可變結構與不可變類對象非常相似,但可變結構和可變類對象是非常不同的。因此,使用不可變結構的代碼通常可以很容易地適應,如果由於某種原因,它有必要改爲使用類對象。

另一方面,如果將其他屬性添加到相關類型中,則使用不可變對象通常會使代碼替換具有更易碎的修改版本的變量。例如,如果一個PhoneNumber類型包括用於AreaCode,LocalExchange和LocalNumber的方法以及一個接受這些參數的構造函數,然後爲Extension添加「可選」第四個屬性,那麼應該更改某些電話號碼的區號的代碼通過將新區域代碼LocalExchange和LocalNumber傳遞給三參數構造函數將刪除每個電話號碼的Extension屬性,而直接寫入AreaCode的代碼不會有這個問題。

0

良好的分析,特別是指出結構是通過值傳遞,因此不會被其他進程改變。

我可以看到的唯一好處是通過使元素的不變性顯式化來實現文體。

0

在面向對象的樣式中,基於對象的類型可以使基於值的類型得到同等對待,這更具有風格。這更多的是個人選擇,我也沒有看到任何一個好處。

0

一般而言,不可變對象比可變對象對系統來說成本較低。可變對象需要具有承擔新值的基礎設施,並且系統必須考慮到它們的值隨時可能發生變化。

可變對象在併發代碼中也是一個挑戰,因爲你必須防止從另一個線程的變化出來的值。但是,如果您不斷創建和銷燬獨特的不可變對象,那麼創建新對象的開銷會變得非常快,代價很高。

在基礎類中,NSNumber是一個不可變的對象。系統維護一個您以前使用過的NSNumber對象池,如果您要求一個具有與您之前創建的值相同的值的數值,則會在您的封面下爲您返回一個現有號碼。

這就是我可以看到使用靜態結構的價值的唯一情況 - 它們不會發生很大的變化,而且可能的值很小。在這種情況下,如果你再次要求一個具有相同值的結構,你可能想用一個「工廠方法」來保存你的類,該工廠方法最近保留了結構並重用了它們。

這樣的方案可以簡化併發代碼,如上所述。在這種情況下,您將不必防範在另一個線程中更改結構的值。如果你使用這樣的結構,你可能知道它永遠不會改變。

1

您對複製值類型的評論非常好。也許這在特定的語言(swift)和特定的編譯器實現(當前版本)中沒有多大意義,但是一般來說,如果編譯器確信數據結構是不可變的,使用參考而不是幕後副本來獲得一些性能改進。出於顯而易見的原因,這不能用可變類型來完成。

更一般地說,限制意味着信息。如果你以某種方式限制你的數據結構,你會獲得一些額外的知識。額外的知識意味着額外的可能性;)也許當前編譯器沒有利用它們,但這並不意味着它們不在這裏:)