Swift中元組(tuples)是如何實現(xiàn)一行代碼交換兩個元素

只是個人研究得出的結(jié)論,可靠性不是很高,如果有說錯的地方,歡迎在評論中指出

Swift中交換兩個元素

(a, b) = (b, a)

示例1:

這個例子說明,確實是將兩個元素的值交換了,而不是創(chuàng)建了局部變量

var a = Person(aName: "1")
var b = Person(aName: "2")
if true {
    // 這里之所以用代碼塊包一層,是為了驗證左邊的元組(a, b)不是創(chuàng)建的一個新的局部變量,而是外部原本的變量
    (a, b) = (b, a)
    print(a.name)   // 2
    print(b.name)   // 1
}
print(a.name)   // 2
print(b.name)   // 1

對比示例2:

這是創(chuàng)建了局部變量的情況。這是賦值給另一個元組,而不是交換元組的兩個元素

var a = Person(aName: "1")
var b = Person(aName: "2")
if true {
   // 如果這里加了let,就變成了定義一個新元組,將右邊的賦值給左邊的新元組(左邊的a, b是新定義的兩個變量,不是原本的了),而不是交換, 所以左邊的(a, b)只是局部變量,只在這個代碼塊中生效
    let (a, b) = (b, a)
    print(a.name)   // 2
    print(b.name)   // 1
}
print(a.name)   // 1
print(b.name)   // 2

拆分步驟

// 第1步
var a = Person(aName: "1")
var b = Person(aName: "2")
// 第2步、第3步
(a, b) = (b, a)

將整個流程分成三步:
1.定義變量a、b
2.創(chuàng)建右邊的元組(b, a)
3.賦值給左邊的元組

第1步

定義變量a、b:定義了兩個Person *指針類型的變量,它們存儲著Person類型的實例
所以a、b本身是Person *類型,他們存有的東西是Person類型(重要的事重復(fù)一遍??)
雖然在swift中已經(jīng)看不到a本身的類型,只有它存儲內(nèi)容是什么類型,但是它應(yīng)該確實是一個指針類型,至少從COC都是這樣的

// 可以看出a本身是<Person *>類型, 它存儲的是一個<Person>類型的東西(啰嗦第三遍了??)
Person *a = [[Person alloc] initWithName:@"1"];
Person *b = [[Person alloc] initWithName:@"2"];

如圖


QQ20200604-120916@2x.png

第2步

創(chuàng)建右邊的元組(b, a):
元組(Tuples)是類似于數(shù)組(Array)的一種列表,在swift中都是值類型。
因為Swift中打印變量的內(nèi)存地址很麻煩,所以這里大膽假設(shè)元組和數(shù)組的存儲原理差不多,然后去OC中研究下是數(shù)組是怎么存儲變量的

通過下圖我們可以看到,array中第一個元素的地址0x2800fd000與a的地址0x16d029350不同,只是他們存有同一個東西0x2802c3ca0

QQ20200604-194943@2x.png

通過查看array的內(nèi)存,可以進一步看到,array中第一個元素的地址是0x2800fd000,第二個元素的地址是0x2800fd032,顯然都不是a、b

QQ20200604-195049@2x.png

所以把a、b兩個變量存入array的過程就是:

1)分配array的內(nèi)存空間,也就是分配連續(xù)兩個Person *類型用的存儲空間。(可以不恰當(dāng)?shù)睦斫鉃閯?chuàng)建了Person *類型的兩個c、d,放到array中)
2)把a里面的東西,復(fù)制一份放到array的第一個空間中(可以不恰當(dāng)?shù)睦斫鉃閷?code>a里面的東西,復(fù)制了一份放到c中)
3)把b里面的東西,復(fù)制一份放到array的第二個空間中(可以不恰當(dāng)?shù)睦斫鉃閷?code>b里面的東西,復(fù)制了一份放到d中)

之后,array基本上和a、b沒啥關(guān)系了

當(dāng)然,這里并不是真的把a里面的實例內(nèi)容完全復(fù)制一份,只是復(fù)制了a實例內(nèi)容的地址。b同理

上圖


QQ20200604-205945@2x.png

類比

類比到元組中,就可以猜測,創(chuàng)建右邊的元組(b, a)這一步操作是:

  • 創(chuàng)建一個元組內(nèi)存空間
  • 依次提取出b、a的值,放到元組中
  • 之后元組(b, a)與原來的變量b變量a基本就沒關(guān)系了。他們只是都保存著相同的東西

第3步

賦值給左邊的元組:
下面是Swift官方文檔中的一段例子

// 你可以將一個元組的內(nèi)容分解(decompose)成單獨的常量和變量,然后你就可以正常使用它們了:
let (statusCode, statusMessage) = http404Error

// 這段代碼也就是
let statusCode = http404Error.0
let statusMessage = http404Error.1

從中就可以發(fā)現(xiàn),元組賦值時,應(yīng)該是將左邊的元組拆分一個個單獨的常量和變量,依次賦值的。

結(jié)論

(a, b) = (b, a) 交換兩個元素,或者更多元素的原理就是

1.將原本變量或常量中的值,存到右邊元組中
2.將左邊元組拆分為一個個變量或常量
2.然后取出右側(cè)元組中的值,依次賦給這些變量或常量

也就是相當(dāng)于
let t = (b, a)
a = t.0
b = t.1

附言

這也就說明了開頭兩個例子差異之處

示例1中
(a, b) = (b, a)

也就是相當(dāng)于
let t = (b, a)
a = t.0   // 這里a就是原本的最早定義的變量a
b = t.1   // 這里b就是原本的最早定義的變量b


對比示例2中
let (a, b) = (b, a)

也就是相當(dāng)于
let t = (b, a)
let a = t.0   // 這里a是定義的一個'新的變量a',只是與外部的變量同名了,二者不是一個
let b = t.1   // 這里b是定義的一個'新的變量b',只是與外部的變量同名了,二者不是一個

因為在示例2中,let (a, b) = (b, a)在代碼塊中,所以被賦值的a、b是局部變量,出了代碼塊就沒了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容