1、什么是值類型
值類型與引用類型相對,值類型的數據特征是,每一個內存實例都會有一份數據copy。在swift語言中,用struct定義的類型都是值類型,這包括了基本數據類型(Int,String,Double,Float),集合類型(Array,Dictionary,Set)等。值類型在賦值和傳遞的過程中,會表現出copy數據的性質。
struct Point {
var x = 0
var y = 0
}
var point1 = Point()
var point2 = point1
我們定義兩個值類型的變量point1、point2,當我們使用point1對point2進行賦值的時候,理論上編譯器會創建point2對象,并將point1的數據進行一次copy賦值給point2。如果我們修改了point2的內容,我們會發現point1的內容并沒有發生變化。
point2.x = 1
print(point2.x) // 1
print(point1.x) // 0, 對point2的修改不會影響point1的內容
2、值類型的優缺點
線程的目標是提升程序的運行效率,但是由于數據在線程之間的共享所帶來的復雜度,大大的削弱了這種性能的提升帶來的好處。甚至在復雜的線程鎖機制下,在某些情況下線程帶來了性能的提升變得微乎其微。值類型的設計可以有效的降低編程問題的復雜度,編譯器保證值類型的數據擁有者都持有一份數據的私有copy,這種數據的私有性可以讓數據的的持有者安全的修改自己的數據,而不需要擔心其它線程可能會修改這些數據而被迫采用使用線程鎖。
因為值類型數據有機會直接在??臻g分配內存,所以可以減少堆上內存分配和回收的次數,這對于要在堆上創建大量的小對象而言,值類型表現出了特有的優勢。但是理論上,值類型在賦值和傳遞的過程中總是需要進行copy會帶來一定性能的影響,swift使用了很多優化機制,來減輕copy帶了的性能影響。
編譯器可以將copy操作延時到不得不進行copy的時候再進行操作(比如常常被提到的“寫時拷貝”),更進一步來說,當一個結構體不要求在內存空間中連續存放的話,那么當發生“寫時copy”的時候,編譯器則完全只處理臟數據的copy,而繼續共享相同內容的數據。
- swift語言的設計者重視值類型,將90%的內容都設計為值類型,而且平等的強調了let與var(在很多語言中默認聲明的都是變量,常量需要用特殊的關鍵字來進行修飾)。swift語言中的let關鍵字與值類型配合可以讓不變性在語義上更加完整。
let array = [1,2,3,4,5]
array.append(6) // error!!!!!!!
如果array是一個引用類型,let的聲明只能限制array不可以再指向其它內容,但let無法限制我們在array所指向的對象中新增內容(既在數據中新增內容)。但此時array是一個值類型,swift編譯器保證用let修飾過的值類型不可變,從而將不變性的語義更加完整。
3、inout
我們現在已經知道,值類型在傳遞的過程中會進行數據的copy,那么顯而易見的是下面改變x的值是不會成功的
var x = 10
func changeX(x: Int) {
x + = 10
}
changeX(x)
print(x) // 10 x的值不會發生改變
如果我們希望x的值可以被改變,那么我們必須使用引用的方式來傳遞x。這時候我們就需要使用inout,當我們使用inout的時候,編譯器不論當前struct的存放狀態如何,都一定會把結構體放入一個連續的內存空間中,并將地址作為參數進行傳遞。
var x = 10
func changeX(x: inOut Int) { // swift3.0改變了inOut修飾符的位置
x + = 10
}
changeX(x)
print(x) // 20 x的值發生了改變