2015-07-18 209 views
11

我已經看過類似的問題,但我還沒有看到我滿意的答案。Swift通過引用傳遞結構?

以引用的方式傳遞結構是可能的還是可取的?如果是這樣如何?

這裏是一個代碼,作爲實例的引用:

struct MyData { 
    var contentId: Int = 0 
    var authorId: Int = 0 
    var image: UIImage = UIImage(named: "myimage") 
} 

正如你看到我這樣做的主要原因是因爲沒有我的形象所有的地方繁殖。

+1

幸運的是,你的圖像是一個引用類型,並且你將通過傳遞對UIImage的引用來傳遞結構的值相同。 –

+0

這將是一個很好的答案與來源 – Esqarrouth

回答

31

使用inout關鍵字和&運算符可以通過引用傳遞結構體。

struct Test { 
    var val1:Int 
    let val2:String 

    init(v1: Int, v2: String) { 
     val1 = v1 
     val2 = v2 
    } 
} 

var myTest = Test(v1: 42, v2: "fred") 

func change(test: inout Test) { 
    // you can mutate "var" members of the struct 
    test.val1 = 24 

    // or replace the struct entirely 
    test = Test(v1: 10, v2: "joe") 
} 
change(test: &myTest) 
myTest // shows val1=10, val2=joe in the playground 

這種做法是不鼓勵的,除非您能證明這是在危急情況下獲得所需性能的唯一途徑。

請注意,這樣做不會節省複製UIImage的負擔。當你把一個引用類型作爲一個結構體的成員時,你仍然只是在你傳值的時候複製引用。您不復製圖像的內容。

關於結構性能的另一個重要知識是copy-on-write。像Array這樣的許多內置類型都是值類型,但它們非常高效。當你在Swift中傳遞一個結構體時,你不會承擔複製它的負擔,直到你改變它爲止。

查看WWDC video on value types瞭解更多。

3

首先,如果您傳遞一個結構體,它通常會按值傳遞。即使該結構的所有屬性被複制僅指針性質,這是引用類型等的UIImage被複制(只有8個字節):

var data1 = MyData() 
var data2 = data1 
// both data1 and data2 point to the same image 

另外的編譯器優化代碼,以便結構得到內部通過引用傳遞和複製如果需要的話。

正如在頂級代碼引用傳遞一個結構的一個例子,你可以使用inout參數: 因此,一個inout參數可以通過引用傳遞,但斯威夫特的實施inout的一般方式是,參數的值後得到通行證函數返回它被重新分配。

儘管編譯器優化了函數調用,所以在某些情況下可以獲得真實的引用。此優化僅影響不計算變量或具有像willSetdidSet(可能還有其他情況)這樣的屬性觀察器。

所以,你應該只依靠目前的實例,它是不是在功能範圍:

struct Test { 
    var value = 0 
} 

// case 1 
var myTest = Test() 

// case 2 
var myTest = Test() { 
didSet { print("I was set") } 
} 

// case 3 
var myTest: Test { 
get{ return Test() } 
set{ print("I set myself") } 
} 

func mutateTest(inout t: Test) { 
    // directly referencing to myTest 

    myTest.value // value = 0 in all cases 

    t.value = 42 
    myTest.value // value = 42 in case 1 ; value = 0 in case 2 and 3 

    t = Test() // nothing gets printed 
    myTest.value // value = 0 in all cases 

    t = Test() // nothing gets printed 
    t.value = 3 // value = 3 in case 1 ; value = 0 in case 2 and 3 
} 

changeTest(&myTest) 
//case 2: "I was set", case 3 "I set myself" get printed now 

myTest.value // value = 3 in all cases 

正如你可以看到myTestt僅在情況下1當量(「真」參考語義) 。因此,如果您在函數本身中也引用了myTest,這會產生巨大的差異。但只要你不這樣做,你就很好。