國外優秀教程精譯 | Swift 可選值詳解(下)

如果看完 Swift 可選值詳解(上)后,你對可選值還是有些迷惑,甚至一頭霧水,那么我們來換一種方式來解釋。
看下面的方法:

func yearAlbumReleased(name: String) -> Int {
    if name == "Taylor Swift" { return 2006 }
    if name == "Fearless" { return 2008 }
    if name == "Speak Now" { return 2010 }
    if name == "Red" { return 2012 }
    if name == "1989" { return 2014 }

    return 0
}

該方法要求傳入一個 Taylor Swift 專輯的名稱,返回對應的發行年份。 但是如果我們傳入了專輯名稱“Lantern”,因為我們將 Taylor Swift 與 Hudson Mohawke 混為一談(這是一個容易犯的錯誤,對吧?),該方法就返回 0,因為它不是 Taylor 的專輯之一。
但 0 在這里有意義嗎? 當然,如果專輯是在公元 0 年發布的,當時凱撒奧古斯是羅馬的皇帝,0 可能有意義,但在這里只會讓人感到困惑 —— 人們需要提前知道 0 的含義是“不被認可”。(譯者注:這里說明的是,0 代表的含義需要提前定義,否者很容易被當作年份處理)
最好是改寫為返回 int (有對應年份時)或 nil (沒有對應年份),可選值使這一切變得容易。下面是改寫后的方法:

func yearAlbumReleased(name: String) -> Int? {
    if name == "Taylor Swift" { return 2006 }
    if name == "Fearless" { return 2008 }
    if name == "Speak Now" { return 2010 }
    if name == "Red" { return 2012 }
    if name == "1989" { return 2014 }

    return nil
}

由于用了可選值,我們需要用 if let 解包,因為需要檢查值是否存在。
再來看另一種情形:

var items = ["James", "John", "Sally"]

現在我們想輸出其中一個名字對應的索引值,我們可能這樣寫:

func position(of string: String, in array: [String]) -> Int {
    for i in 0 ..< array.count {
        if array[i] == string {
            return i
        }
    }

    return 0
}

其中循環檢查了數組成員,返回了對應名稱的索引值,如果沒找到,返回 0 。
現在試著運行下面 4 行代碼:

let jamesPosition = position(of: "James", in: items)
let johnPosition = position(of: "John", in: items)
let sallyPosition = position(of: "Sally", in: items)
let bobPosition = position(of: "Bob", in: items)

將輸出 0, 1, 2, 0 —— James 和 Bob 的位置是一樣的,然而他們實際上一個存在,而另一個并不存在。這是因為我用 0 表示 “不存在” 造成的。圖省事的話,可以用 -1 來表示不存在,但這樣一來,又必須時刻記得有這個特殊值意味著“不存在”。(譯者注:-1 引發的崩潰相信大家都有經歷過,在 C 語言中,有符號 -1 轉換為無符號時,為無符號的最大值,從而導致很多混亂)
解決辦法還是可選值:用 nil 表示沒有找到對應名稱。這也是數組內置查找方法 someArray.firstIndex(of: someValue)的實際做法。
當你要對付“可能有可能沒有”的值,Swfit 強制要求在使用前解包,以此明確這里可能沒有值。if let就是用來做這個的:如果有值就解包后使用,否者完全不使用它。Swift 根本不讓你憑空地使用一個可能為空的值。

強制解包

Swift 允許使用感嘆號 !來屏蔽它的安全性。當你能確認可選值有值時,可以將感嘆號放在這個值后面來強制解包它。

請小心:如果你強制解包一個沒有值的可選值時,會引發代碼崩潰。

下面是一些協同工作的代碼:

func yearAlbumReleased(name: String) -> Int? {
    if name == "Taylor Swift" { return 2006 }
    if name == "Fearless" { return 2008 }
    if name == "Speak Now" { return 2010 }
    if name == "Red" { return 2012 }
    if name == "1989" { return 2014 }

    return nil
}

var year = yearAlbumReleased(name: "Red")

if year == nil {
    print("There was an error")
} else {
    print("It was released in \(year)")
}

代碼獲得了專輯的發行年份。如果沒找到專輯,year被置空,將打印出錯信息。否則正確的發行年份會被打印。
是嗎?好吧,因為 yearAlbumReleased()返回的是可選值,這里由沒有使用 if let來解包。結果,實際輸出的是“It was released in Optional(2012)”——可能并不是我們想要的。
關鍵是,我們已經檢查了可選值的有效性,再用 if let進行所謂的安全解包顯得有點無意義。因此,Swift 提供了解決辦法——把上面代碼中第二個print() 改為這樣:

print("It was released in \(year!)")

注意這個感嘆號:它的意思是“我保證這里有值,強制解包吧”。

隱形解包

你還能用感嘆號來創建隱形解包可選值,這是很多人真正感到困惑的地方。那么就好好讀讀下面的介紹。

  • 靜態變量必須含有值。比如:String 必須含有 string ,哪怕是空字符串"",不能為 nil 。
  • 可選值可以有值也可以沒有。使用前必須解包。比如 String? 可能為 string ,或者是 nil ,確定的辦法就是解包。
  • 隱形解包可選值可以有值也可以沒有。但使用前不需要解包。Swift 不再為你檢查,所以你使用時要額外小心。比如 String! 可能為 string ,或者是 nil ——取決于你適當的使用它。它類似靜態變量,Swift 允許你直接訪問它的值,不需要安全地解包。如果你要這么做,意味著你知道一定有值,否者程序會崩。

使用隱形解包可選值的主要情形是在使用 UIKit 的界面元素時(macOS 里對應 AppKit ),這些需要事先聲明,但是在創建之前你不能使用它們 —— 而 Apple 喜歡在最后一刻創建用戶界面元素以避免任何不必要的工作。 必須不斷地打開你肯定知道的值,這會使人厭煩,所以這些是隱式解開的。
不要擔心,如果您發現隱式解包的選項有點難以理解 - 當您使用該語言時,它將變得清晰。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容