swift的值型別與inout

weixin_33895657發表於2016-07-16

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,這種資料的私有性可以讓資料的的持有者安全的修改自己的資料,而不需要擔心其它執行緒可能會修改這些資料而被迫採用使用執行緒鎖。

  • 因為值型別資料有機會直接在棧空間分配記憶體,所以可以減少堆上記憶體分配和回收的次數,這對於要在堆上建立大量的小物件而言,值型別表現出了特有的優勢。但是理論上,值型別在賦值和傳遞的過程中總是需要進行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的值發生了改變

相關文章