理解 Swift 的值語(yǔ)義

棧中兩個(gè)值類(lèi)型的概念草圖

即使你剛剛開(kāi)始編程家凯,也可能會(huì)無(wú)意間了解到值類(lèi)型缓醋。而更有可能的是你根本沒(méi)有意識(shí)到自己在使用它們,但它們帶有一些有趣和不可不知的屬性绊诲,我將在下文中介紹它們送粱。

什么是值類(lèi)型?

你可能知道 class 是引用類(lèi)型掂之,并且可以在不同變量之間共享對(duì)象的引用抗俄。你可能還知道,可以通過(guò)引用同一個(gè)對(duì)象的多個(gè)變量來(lái)改變?cè)搶?duì)象的狀態(tài)世舰,如下所示:

class MyReferenceType {
  var a: Int
  init(a: Int) {
    self.a = a
  }
}
var R1 = MyReferenceType(a: 1)
var R2 = R1
R2.a = 42
print(R1.a, R2.a)
// 打印 "42 42"

許多不同的變量能夠改變同一個(gè)對(duì)象的事實(shí)有時(shí)被稱(chēng)為“別名問(wèn)題”动雹,如果你不小心的話(huà),它可能產(chǎn)生一些非常難以跟蹤的錯(cuò)誤跟压。
另一方面胰蝠, 值類(lèi)型的行為更像我們期望的標(biāo)準(zhǔn)基礎(chǔ)類(lèi)型的行為。這意味著你期望 intdoublefloat 所做所有的事情茸塞,值類(lèi)型也都能做到躲庄。比如說(shuō)在執(zhí)行下面的操作時(shí),你會(huì)期望變量 b 擁有自己可修改的數(shù)字(42)的副本钾虐,而且當(dāng)它改變時(shí)變量 a 不受影響:

var a: Int = 42
var b: Int = a
b = 0
print(a, b)
// 打印 "42 0"

這種語(yǔ)義也擴(kuò)展到了其它值類(lèi)型噪窘,在 Swift 中 struct 是值類(lèi)型,enumtuple 也是效扫。這就是說(shuō)只要為變量被賦值給另一個(gè)變量倔监,就會(huì)分配一個(gè)新對(duì)象。下面的代碼中荡短,修改 v2 不會(huì)影響 v1 的值:

struct MyValueType {
  var a: Int
}
var V1 = MyValueType(a: 1)
var V2 = V1
V2.a = 42
print(V1)
// 打印 "MyValueType(a: 1)"
print(V2)
// 打印 "MyValueType(a: 42)"

繼續(xù)深入……

正如在上一節(jié)所看到的那樣丐枉,引用類(lèi)型值類(lèi)型在一些非常容易理解的基本方式上有所不同。但也有一些時(shí)候掘托,它們之間的界限變得模糊了瘦锹,比如說(shuō) Array (它是個(gè)struct)。我們將借助一個(gè)工具方法闪盔,它使我們能夠比較內(nèi)存地址弯院,以便更深入地了解所發(fā)生的情況:

func address(of pointer: UnsafeRawPointer) -> String {
  let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
  let address = Int(bitPattern: pointer)
  return String(format: "%0\(length)p", address)
}
var V1 = [Int]()
var V2 = V1
print(address(of: &V1) == address(of: &V2))
// 打印 "true"
V1 = [Int]()
V2 = [Int]()
print(address(of: &V1) == address(of: &V2))
// 打印 "true"

什么情況?即使我們的數(shù)組是個(gè)值類(lèi)型泪掀,當(dāng)它被賦值給變量 v2 時(shí)听绳,也不會(huì)復(fù)制到新的內(nèi)存地址。即使我們?yōu)槊總€(gè)變量創(chuàng)建并分配數(shù)字實(shí)例异赫,它們也不會(huì)落在不同的內(nèi)存地址上椅挣,到底怎么回事?
Swift 編譯器很聰明塔拳,它會(huì)做一大通優(yōu)化鼠证,以確保程序消耗盡可能少的資源。在上面的實(shí)例中靠抑,編譯器注意到了這兩個(gè)變量指向兩個(gè)相等的數(shù)據(jù)量九,由于它們?cè)趫?zhí)行期間沒(méi)有改變,可以通過(guò)分配一個(gè)實(shí)例然后將我們的變量指向同一個(gè)實(shí)例來(lái)節(jié)省一些內(nèi)存和執(zhí)行時(shí)間颂碧。這種共享后資源無(wú)任何改變的行為被稱(chēng)作“寫(xiě)時(shí)復(fù)制(Copy-On-Write)”荠列。

寫(xiě)時(shí)復(fù)制機(jī)制

Swift 中一大堆值類(lèi)型都實(shí)現(xiàn)了寫(xiě)時(shí)復(fù)制(COW)行為,這就是說(shuō)只要不發(fā)生修改载城,多個(gè)變量會(huì)指向相同的內(nèi)存位置肌似。如果某個(gè)變量想要改變數(shù)據(jù),它將被分配新的內(nèi)存并復(fù)制內(nèi)容诉瓦,然后在新內(nèi)存地址上調(diào)整結(jié)構(gòu)锈嫩。實(shí)際上受楼,持有 COW 值的變量不像非 COW 變量那樣對(duì)該值享有“專(zhuān)有權(quán)”。在我們的例子調(diào)用 address 方法顯示 v2 申請(qǐng)了它自己的內(nèi)存并將 v1 的值拷貝了過(guò)去呼寸,在某種意義上第一個(gè) MyValueType 對(duì)象將為 v1 所專(zhuān)有艳汽。
為了證明分配初始值的變量不一定是保留它的變量,我將貼一張 XCode Playground 的截圖对雪『雍看一下里面打印的內(nèi)存地址,可以發(fā)現(xiàn)由于第一個(gè)變量想要在共享之后改變底層的值瑟捣,不得不放棄初始化時(shí)分配的地址和對(duì)象馋艺,改而分配新的內(nèi)存:

以上就是所有要介紹的內(nèi)容,如果你想了解有關(guān)值類(lèi)型的更多信息以及它可能為你的項(xiàng)目帶來(lái)哪些優(yōu)勢(shì)迈套,建議觀看 WWDC 2015 上蘋(píng)果的演示文稿捐祠。


原文:https://medium.com/@JimmyMAndersson/understanding-swift-value-semantics-d84d57b937a2
作者:Jimmy M Andersson
編譯:碼王爺

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市桑李,隨后出現(xiàn)的幾起案子踱蛀,更是在濱河造成了極大的恐慌,老刑警劉巖贵白,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件率拒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡禁荒,警方通過(guò)查閱死者的電腦和手機(jī)猬膨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)呛伴,“玉大人勃痴,你說(shuō)我怎么就攤上這事∪瓤担” “怎么了沛申?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)褐隆。 經(jīng)常有香客問(wèn)我污它,道長(zhǎng)剖踊,這世上最難降的妖魔是什么庶弃? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮德澈,結(jié)果婚禮上歇攻,老公的妹妹穿的比我還像新娘。我一直安慰自己梆造,他們只是感情好缴守,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布葬毫。 她就那樣靜靜地躺著,像睡著了一般屡穗。 火紅的嫁衣襯著肌膚如雪贴捡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天村砂,我揣著相機(jī)與錄音烂斋,去河邊找鬼。 笑死础废,一個(gè)胖子當(dāng)著我的面吹牛汛骂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播评腺,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼帘瞭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蒿讥?” 一聲冷哼從身側(cè)響起蝶念,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诈悍,沒(méi)想到半個(gè)月后祸轮,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侥钳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年适袜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舷夺。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苦酱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出给猾,到底是詐尸還是另有隱情疫萤,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布敢伸,位于F島的核電站扯饶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏池颈。R本人自食惡果不足惜尾序,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望躯砰。 院中可真熱鬧每币,春花似錦、人聲如沸琢歇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至揭保,卻和暖如春肥橙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秸侣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工快骗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人塔次。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓方篮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親励负。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藕溅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔,今天18年5月份再次想寫(xiě)文章继榆,發(fā)現(xiàn)簡(jiǎn)書(shū)還為我保存起的...
    Jenaral閱讀 2,733評(píng)論 2 9
  • 參考資源《swifter》https://github.com/iOS-Swift-Developers/Swif...
    柯浩然閱讀 1,430評(píng)論 0 6
  • Java8張圖 11巾表、字符串不變性 12、equals()方法略吨、hashCode()方法的區(qū)別 13集币、...
    Miley_MOJIE閱讀 3,693評(píng)論 0 11
  • 普通人跟瘋子之間的聯(lián)系 瘋子看起來(lái)會(huì)相信看起來(lái)根本不符合邏輯的觀點(diǎn),但是我們往往忽略了正常人也是這樣的翠忠,只不過(guò)瘋子...
    Wilbur_閱讀 193評(píng)論 0 1