只是個人研究得出的結(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)該確實是一個指針類型,至少從C到 OC都是這樣的
// 可以看出a本身是<Person *>類型, 它存儲的是一個<Person>類型的東西(啰嗦第三遍了??)
Person *a = [[Person alloc] initWithName:@"1"];
Person *b = [[Person alloc] initWithName:@"2"];
如圖

第2步
創(chuàng)建右邊的元組(b, a):
元組(Tuples)是類似于數(shù)組(Array)的一種列表,在swift中都是值類型。
因為Swift中打印變量的內(nèi)存地址很麻煩,所以這里大膽假設(shè)元組和數(shù)組的存儲原理差不多,然后去OC中研究下是數(shù)組是怎么存儲變量的
通過下圖我們可以看到,array中第一個元素的地址0x2800fd000與a的地址0x16d029350不同,只是他們存有同一個東西0x2802c3ca0

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

所以把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同理
上圖

類比
類比到元組中,就可以猜測,創(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是局部變量,出了代碼塊就沒了