[英]Inout in swift and reference type
我試圖了解值和引用類型之間的區別。 現在我想使用蘋果指南中的功能:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
如果我想使用這個功能,我會寫這段代碼
swapTwoInts{&firstIntStruct, &secondIntStruct}
我知道我們必須放入此函數引用類型,但是Int是值類型,因此我們使用&。
另一方面,當我嘗試在交換函數中將Int更改為我的班級時,我還必須在班級實例之前編寫&。
如果已經是參考文獻,為什么我必須這樣做?
假設我們編寫了您正在談論的假設函數:
class C {}
func swapTwoC(_ lhs: C, rhs: C) {
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
直接的問題是lhs
和rhs
是不可變的。 要對其進行變異,我們需要制作可變的副本:
func swapTwoC(_ lhs: C, rhs: C) {
var lhs = lhs; var rhs = rhs
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
但是現在的問題是,我們正在變異我們的副本,而不是調用者給我們的原始引用。
從根本上講,問題在於,當您將對函數的引用(對類的實例,我們稱為對象)傳遞給函數時,該引用本身即被復制(其行為類似於值類型)。 如前所述,如果該函數更改了引用的值,它只會使它自己的本地副本發生變異。
當您有一個inout C
並傳入&myObject
,實際上要傳入的是對myObject
的引用 。 復制函數參數時,復制的內容是“引用到引用”。 然后,該函數可以使用該“引用到引用”將新值分配給調用方具有的引用myObject
因此,有一些較低級別的內存組件正在發揮作用,以充分理解這一點。
1)創建值或引用類型時,堆棧上會有一個新變量。 在值類型的情況下,該變量是實際數據,在引用類型的情況下,該變量是數據的指針。
2)調用函數時,它將創建堆棧的新部分,並在堆棧上創建新的變量(即let
實例迅速存儲),該變量將復制傳入的變量。因此,對於值類型,它將執行深度復制,對於引用類型它復制指針。
所以這意味着當您使用inout
您要說的是獲取此變量的內存地址並更新其包含的數據。 因此,您可以為值類型提供新的數據,也可以為引用類型提供新的指針地址,它將在交換功能的范圍之外更改。 它使它成為一個var
(與傳入的內容相同),而不是像普通的那樣let
。
我想舉例說明。 如@Alexander所述,對於將Int
作為參數的函數:
1.傳遞價值
它將更改副本,而不是調用方的原始引用。
從根本上講,問題在於,當您將對函數的引用(對類的實例,我們稱為對象)傳遞給函數時,該引用本身即被復制(其行為類似於值類型)。 如前所述,如果該函數更改了引用的值,它只會使它自己的本地副本發生變異。
你可以看到
func swapTwoInts(_ a: Int, _ b: Int) { }
如果更改了p和q的值,則self.x和self.y不變。 由於此函數傳遞x和y的值而不是它們的參考。
2.通過引用傳遞:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { }
它通過了self.x和self.y的引用,這就是為什么您不必像以前那樣通過將p和q取為先前的類型來再次對其進行突變的原因。 因為它將使用var x
和var y
來使對象變異。
您可以看到,a和b在日志中具有引用的值,並且更改a和b也更改了self.x和self.y ,因為a和b具有相同的x和y的引用(地址)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.