Swift 是一門非常安全的語(yǔ)言,這里指的是 Swift 在防止代碼意外崩潰方面做了很多努力。
代碼崩潰的一個(gè)常見原因是試圖使用一個(gè)已損壞的或不存在的數(shù)據(jù)。舉例來(lái)說,假設(shè)有一個(gè)方法:
func getHaterStatus() -> String {
return "Hate"
}
該方法沒有任何參數(shù)钦椭,并且返回一個(gè) string:“Hate”。然而有一天陽(yáng)光明媚碑诉,這些心有怨恨的家伙們不感到怨恨了——會(huì)發(fā)生什么事彪腔?我們可能就不想返回任何東西了:畢竟這些人今天不怨恨了嘛。
這時(shí)进栽,一個(gè)空字符串也許是最好用來(lái)表明“沒啥事”的德挣,有時(shí)這也是事實(shí)。但是用數(shù)字如何表現(xiàn)“什么都沒有”—— 用 0 表示“空數(shù)字”還是 -1 泪幌?
別急著定義你自己的表示規(guī)則盲厌,Swift 已經(jīng)有了解決方案:可選值』隼幔可選值就是可能有值也可能沒有值的變量吗浩。大多數(shù)人都覺得可選值很難理解,別擔(dān)心——我將用各種方式來(lái)說明它没隘,總有一種方式適合你懂扼。
當(dāng)使用 -> String
時(shí),表示“這個(gè)方法會(huì)返回一個(gè)確定的 string ”右蒲,即表示該方法不會(huì)返回空值阀湿,因此它被稱為安全的,因?yàn)槟憧偸悄塬@得一個(gè)值瑰妄,這個(gè)值類型是 string 陷嘴。反之,如果方法可能返回有值或空值间坐,需要改寫為下面這樣:
func getHaterStatus() -> String? {
return "Hate"
}
注意這個(gè)額外的問號(hào) String?
代表“可選的 string ”灾挨。當(dāng)前的代碼無(wú)論如何都會(huì)返回 “Hate”,讓我們來(lái)修改一下:如果天氣晴朗竹宋,懷恨者們將展開新的生活篇章劳澄,放棄他們仇恨的生活,因此返回空值蜈七。在 Swift 中秒拔,空值有特別的關(guān)鍵字: nil
。
于是代碼改為這樣:
func getHaterStatus(weather: String) -> String? {
if weather == "sunny" {
return nil
} else {
return "Hate"
}
}
方法接受一個(gè) string 參數(shù)(天氣 weather )并返回一個(gè) string (仇恨狀態(tài))飒硅,但返回值可能有也可能沒有——為 nil 砂缩。具體到本文例子中作谚,就表示我們可能得到一個(gè) string ,或者得到 nil 梯轻。
那么重點(diǎn)來(lái)了:Swift 希望你的代碼是真正安全的食磕,使用 nil 就不是一個(gè)好主意尽棕。它會(huì)使你的代碼崩潰喳挑,混淆你的代碼邏輯,或者在界面上顯示錯(cuò)誤的內(nèi)容滔悉。因此伊诵,當(dāng)聲明一個(gè)值為可選值之時(shí),Swift 就要確保你能安全地處理它回官。
試著把下面這行添加到你的 playground :
var status: String
status = getHaterStatus(weather: "rainy")
第一行創(chuàng)建一個(gè) string 型變量曹宴,第二行把 getHaterStatus()
的返回值賦值給這個(gè)變量——參數(shù)表示今天下雨,這樣可以保證仇恨者們正在仇恨中(返回值是"Hate”)歉提。
這段代碼無(wú)法運(yùn)行笛坦,因?yàn)槲覀兟暶鞯?String 型變量 status 要求一個(gè)值,但getHaterStatus()
可能無(wú)法提供苔巨,因?yàn)樗祷乜蛇x值版扩。也就是說,我們表示 status 一定是個(gè) string 侄泽,但實(shí)際上 getHaterStatus()
可能啥也不返回礁芦。Swift 根本不會(huì)讓你犯這個(gè)錯(cuò)誤,這非常有用悼尾,因?yàn)樗行У刈柚沽艘淮蠖殉R婂e(cuò)誤柿扣。
為了解決這個(gè)問題,我們需要把 status
聲明為 String?
闺魏,或者干脆移除類型聲明未状,讓 Swift 自己推斷類型。第一種方法如下:
var status: String?
status = getHaterStatus(weather: "rainy")
第二種方式:
var status = getHaterStatus(weather: "rainy")
無(wú)論選擇哪個(gè)析桥,值都可能為空值司草,Swift 是不會(huì)讓你冒險(xiǎn)使用的。舉例來(lái)說烹骨,假設(shè)有這么一個(gè)方法:
func takeHaterAction(status: String) {
if status == "Hate" {
print("Hating")
}
}
這段代碼接受一個(gè) string 翻伺,根據(jù) string 內(nèi)容打印一條消息。這個(gè)方法接受一個(gè) String
值沮焕,卻不是 String?
——你無(wú)法傳遞一個(gè)可選值給它吨岭,它需要一個(gè)確切的值,導(dǎo)致無(wú)法把 status
變量傳給它峦树。
Swift 有兩個(gè)解決辦法辣辫。兩個(gè)都能用旦事,但只能二選一。第一個(gè)解決方案是解包急灭,它在條件語(yǔ)句中使用特定的語(yǔ)法規(guī)則姐浮。解包一次性做兩件事情:檢查可選值是否有值,如果有值就將其放入一個(gè)非可選值中并運(yùn)行對(duì)應(yīng)代碼塊葬馋。
解包語(yǔ)法如下:
if let unwrappedStatus = status {
// unwrappedStatus 是非可選值
} else {
// 解包失敗的處理
}
if let
在一行代碼中簡(jiǎn)潔地處理了檢查和解包卖鲤,這種方法非常常見。應(yīng)用這種方法畴嘶,我們能安全地把 getHaterStatus()
解包蛋逾,并僅在非可選 string 有效存在時(shí),才調(diào)用 takeHaterAction()
窗悯。
這是完整代碼:
func getHaterStatus(weather: String) -> String? {
if weather == "sunny" {
return nil
} else {
return "Hate"
}
}
func takeHaterAction(status: String) {
if status == "Hate" {
print("Hating")
}
}
if let haterStatus = getHaterStatus(weather: "rainy") {
takeHaterAction(status: haterStatus)
}