Swift值型別和引用型別

zhangao0086發表於2014-08-20

原文地址:https://developer.apple.com/swift/blog/?id=10

Swift中的型別分為兩類:一,值型別(value types),每個值型別的例項都擁有各自唯一的資料,通常它們是結構體,列舉或元組;二,引用型別(reference types),引用型別的例項共享它們的資料,通常是一個類。在這篇文章中我們將會探索值型別和引用型別的價值,以及如何在它們二者間抉擇。

有什麼區別?

值型別最基本的特徵就是複製在賦值、初始化和傳遞引數過程中的資料,併為這個資料建立一個獨立的例項:
// 值型別例子
struct S { var data: Int = -1 }
var a = S()
var b = a						// 把a複製給b
a.data = 42						// a被改變了, b卻沒有
println("(a.data), (b.data)")	// prints "42, -1"

複製一個引用型別的時候,其實是隱式地建立了一個共享的例項。在複製後,兩個例項指向了同一塊資料,所以當修改其中一個例項資料的時候,另一個例項的資料也被修改了,比如:

// 引用型別的例子
class C { var data: Int = -1 }
var x = C()
var y = x						// x被複制給了y
x.data = 42						// x指向的資料被修改了 (同時y也被修改了)
println("(x.data), (y.data)")	// prints "42, 42"

可變性在安全中的作用

選擇值型別而不是引用型別的一個主要原因是能讓你的程式碼變得更加簡單。你在任何情況下用一個值型別,都能夠假設你的其他程式碼不會使它改變,這通常在多執行緒環境中很有用,如果一個執行緒中使用的資料被另一個執行緒給意外的修改了,這通常會產生非常嚴重的Bug,且相當難以除錯。
由於只有當你需要修改資料時兩者的區別才會得到體現,所以當你的例項不會對資料進行修改的時候,值型別和引用型別看起來是完全相同的。
你也許會想,寫一個完全不可變的類,這或許是有價值的,使用Cocoa的NSObject能簡化這個過程,並且能很好地保持原有的語義。現在,你能通過使用不可變的儲存屬性,以及避免暴露修改資料的介面,從而在Swift裡實現一個不可變的類。事實上,大多數的Cocoa類,比如NSURL等,都被設計為不可變的類,然而,Swift當前並沒有提供任何語言機制去強制申明一個類不可改變(比如子類化就能修改一個類的實現),只有結構體和列舉才是強制不可變的。

如何選擇?

所以如果你想要建立一個新的型別,你怎麼選擇?當你寫Cocoa程式的時候,大多數APIs都需要從NSObject繼承,你就已經是一個類了(引用型別),針對其他情況,這裡有些指導規則:
使用值型別,當…:
  • 通過使用==去比較例項的資料
  • 你想得到一個例項的獨立副本
  • 資料在多執行緒環境下被修改
使用引用型別(比如使用一個類),當…:
  • 通過使用===去判斷兩個例項是否恆等
  • 你想要建立一個共享的,可變的物件
在Swift裡,Array、String和Dictionary都是值型別,他們的行為和C語言中的int類似,每個例項都有自己的資料,你不需要額外做任何事情,比如做一個顯式的copy,防止其他程式碼在你不知情的情況下修改等,更重要的是,你能安全地線上程間傳遞它,而不需要使用同步技術。在提高安全性的精神下,這個模型將幫助你在Swift中寫出更多可預知的程式碼。


相關文章