Swift-值類型與引用類型

Swift-值類型與引用類型

Swift類型有兩個類別,第一為值類型,每個實例中各保存唯一的副本,通常被定義成struct、enum或tuple,第二為引用類型,每個實例共享一個單一的副本,通常被定義成像類別(class),在這篇文章我們要來討論值類型與引用類型以及如何在它們之間選擇。

值類型

值類型的最基本的特點是複制,它分配、初始化、參數傳遞,建立一個與自已獨立的副本,例如:

struct S { var data: Int = 1 }
var a = S()
var b = a
a.data = 20
println("\(a.data), \(b.data)")

輸出結果:

20, 1

引用類型

複制引用,另一方面,隱式的建立一個共享實例,複制後,兩個變數都參考同一個單一實例,以便修改第二個數值時也能原來的同步,例如:

// Reference type example
class C { var data: Int = 1 }
var x = C()
var y = x
x.data = 20
println("\(x.data), \(y.data)")

輸出結果:

20, 20

兩種的安全性

有一個主要的理由解釋選擇值類型勝過引用類型就是能更容易的理解你寫的程式。如果你總是得到獨特、複制的實例,你可以相信沒有在程式其他地方可以變更你的資料,這種情形在多線程的環境中非常有幫助,像其他線程可以在其他情況改變你的資料時,這可能會引其其他的錯誤,也會令你很難去除錯。

由於這兩種類型被定義當你改變資料時是不同的處理方式,不過有一種特例值類型與引用類型功能是相似的,那就是當你的實例不寫入資料只讀資料時,值類型與引用類型的功能就是相同的。

你可能會想那是有價值的,如果一個情況class是不可變的。它能使你更容易去使用NSObject物件維護並保持原來的語義。現在,你可以在Swift中寫一個不可變的類別並籍著使用不可變的存儲屬性避免暴露任何可以修改狀態的API。事實上,很多Cocoa類別,像NSURL被設計成不可變類別。然而,Swift並沒有提供任何語言的機制去施行類別像struct、enum一樣成為不可變(像子類別)。

兩種適用的用途

所以,如果你想建立一個新的類型,你怎麼決定要哪一種?當你使用Cocoa,許多API預計都是NSObject的子類,所以你必須使用一個類。對於其他情況,這裡有一些建議:

使用值類型

  • 比較實例的資料內容
  • 你想要拷貝成獨立的狀態
  • 你的資料被使用在多個線程中

使用引用類型

  • 比較實例是否引用同一個類
  • 你想要建立一個共享可變的狀態

結語:

在Swift中,陣列、字串、字典都是值類型,它們有著類似C的int,資料都有一個獨立的實例,你不需要做任何特別的事,像是做一個明確的拷貝副本、程式在你背後隨意的變更資料,你都能安全的在多線程更改資料,不需要去對資料做同步,這在你寫程式時都很有幫助。

參考資訊

Value and Reference Types