Swift中的問(wèn)號(hào)?和感嘆號(hào)!

在 C 和 Objective-C 中,沒(méi)有可選項(xiàng)的概念。在 Objective-C 中有一個(gè)近似的特性,一個(gè)方法可以返回一個(gè)對(duì)象或者返回 nil 。 nil 的意思是“缺少一個(gè)可用對(duì)象”。然而,他只能用在對(duì)象上,卻不能作用在結(jié)構(gòu)體,基礎(chǔ)的 C 類型和枚舉值上。對(duì)于這些類型,Objective-C 會(huì)返回一個(gè)特殊的值(例如 NSNotFound )來(lái)表示值的缺失。這種方法是建立在假設(shè)調(diào)用者知道這個(gè)特殊的值并記得去檢查他。然而,Swift 中的可選項(xiàng)就可以讓你知道任何類型的值的缺失,他并不需要一個(gè)特殊的值,它強(qiáng)調(diào)的是有沒(méi)有,而非空不空。

可以利用可選項(xiàng)來(lái)處理值可能缺失的情況??蛇x項(xiàng)意味著:這里有一個(gè)值,他等于x或者根本沒(méi)有值

swift里面常量/變量的聲明方式:

聲明常量 let 聲明變量 var
1? let name = "swift"或let name: String = "swift" 6? var name = "swift"var name: String = "swift"
2? let name: String 7? var name: String
3?let name: String?(或!) = "swift" 8? var name: String?(或!) = "swift"
4? let name: String? 9? var name: String?
5? let name: String! 10 var name: String!

普通類型

常量/變量聲明的時(shí)候類型后面不帶有?或者!為普通類型,也就是上表中1?, 2?, 6?,7?聲明方式

  • 要么在聲明的時(shí)候賦初始值,要么在其所屬類的初始化方法中賦初始值,才能參與運(yùn)算
  • 這種類型沒(méi)有默認(rèn)初始值,且生命周期中不能接收nil

可選項(xiàng)(Optional Type)

常量/變量聲明的時(shí)候類型后面帶有?或者!為可選類型(optional type,即可選項(xiàng)),也就是上表中3?,4?,5?,8?,9?,10聲明方式。
此外let name: Optinal<String> 的簡(jiǎn)寫形式是4?,二者作用跟和用法是完全一樣的; 同理let name: ImplicitlyUnwrappedOptional<String>的簡(jiǎn)寫形式是5?,二者作用跟和用法也是完全一樣。

  • 聲明為Optional常量時(shí)如果沒(méi)有賦初始值,此常量沒(méi)有默認(rèn)值,需要在構(gòu)造函數(shù)中給常量設(shè)置初始數(shù)值
  • 聲明為Optional的變量,如果不顯式的賦值就會(huì)有個(gè)默認(rèn)值nil
  • 聲明為Optional的變量/常量不能直接參與運(yùn)算,必須解包后才能參與運(yùn)算
  • 解包后的Optional變量/常量如果沒(méi)有值(為nil)參與運(yùn)算也會(huì)發(fā)生Crash

我們可以對(duì)一個(gè)可選項(xiàng)類型(Optional Type)使用后綴操作符!來(lái)強(qiáng)制拆包(force unwrap)訪問(wèn)這個(gè)值,來(lái)繼續(xù)后面的操作。
可選類型類似于Objective-C中指針的nil值,但是nil只對(duì)類(class)有用,而swift中可選類型對(duì)所有的類型都可用,并且更安全。

強(qiáng)制展開

如果一個(gè)可選有值,它“不等于” nil ,可以通過(guò)比較 nil 來(lái)判斷一個(gè)可選中是否包含值。
一旦你確定可選中包含值,可以使用后綴操作符!來(lái)強(qiáng)制拆包(force unwrap)訪問(wèn)這個(gè)值,,感嘆號(hào)的意思就是說(shuō)“我知道這個(gè)可選項(xiàng)里邊有值,展開吧?!边@就是所謂的可選值的強(qiáng)制展開。

var myString:String?
myString = "Hello, Swift!"

if myString != nil {
   print(myString)  //prints:Optional("Hello, Swift!")
   // 強(qiáng)制展開
   print(myString!)  //prints:Hello, Swift!
}else{
   print("myString 值為 nil")
}

注意:
使用 ! 來(lái)獲取一個(gè)不存在的可選值會(huì)導(dǎo)致carsh,在使用!強(qiáng)制展開之前必須確??蛇x項(xiàng)中包含一個(gè)非 nil 的值。

可選項(xiàng)綁定

可以使用可選項(xiàng)綁定來(lái)判斷可選項(xiàng)是否包含值,如果包含就把值賦給一個(gè)臨時(shí)的常量/變量??蛇x綁定可以與 if 和 while 的語(yǔ)句使用來(lái)檢查可選項(xiàng)內(nèi)部的值,并賦值給一個(gè)變量或常量。

var myString:String?
myString = "Hello, Swift!"

if let yourString = myString {
   print("你的字符串值為 - \(yourString)")
}else{
   print("你的字符串沒(méi)有值")
}
//prints:你的字符串值為 - Hello, Swift!

隱式展開

有時(shí)在一些程序結(jié)構(gòu)中可選項(xiàng)一旦被設(shè)定值之后,就會(huì)一直擁有值。在這種情況下,就可以去掉檢查的需求,不必每次訪問(wèn)的時(shí)候都進(jìn)行展開,因?yàn)樗梢园踩拇_認(rèn)每次訪問(wèn)的時(shí)候都有一個(gè)值。這種類型的可選項(xiàng)被定義為隱式展開可選項(xiàng)。
通過(guò)在類型后邊添加一個(gè)嘆號(hào)( String! )而非問(wèn)號(hào)( String? ) 來(lái)聲明一個(gè)隱式展開可選項(xiàng)。
在可選項(xiàng)被定義的時(shí)候就能立即確認(rèn)其中有值的情況下,隱式展開可選項(xiàng)非常有用,主要被用在 Swift 類的初始化過(guò)程中。
下面的栗子展示了在訪問(wèn)被明確為 String 的可選項(xiàng)展開值時(shí),可選字符串和隱式展開可選字符串的行為區(qū)別:

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
 
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark

你可以把隱式展開可選項(xiàng)當(dāng)做在每次訪問(wèn)它的時(shí)候被給予了自動(dòng)進(jìn)行展開的權(quán)限(編譯器自動(dòng)在操作前補(bǔ)上一個(gè)!進(jìn)行拆包,然后在執(zhí)行后面的操作,當(dāng)然如果該值是nil,也一樣會(huì)報(bào)錯(cuò)crash掉),這樣就可以在聲明可選項(xiàng)的時(shí)候添加一個(gè)嘆號(hào)而不是每次調(diào)用的時(shí)候在可選項(xiàng)后邊添加一個(gè)嘆號(hào)。
你可以像對(duì)待普通可選一樣對(duì)待隱式展開可選項(xiàng)來(lái)檢查里邊是否包含一個(gè)值:

if assumedString != nil {
    print(assumedString)
}
// prints "An implicitly unwrapped optional string."

你也可以對(duì)待隱式展開可選項(xiàng)通過(guò)可選項(xiàng)綁定在一句話中檢查和展開值:

if let definiteString = assumedString {
    print(definiteString)
}
// prints "An implicitly unwrapped optional string."

合并空值運(yùn)算符

上面對(duì)可選類型的三種處理不是需要繁瑣的判斷就是存在Crash風(fēng)險(xiǎn)不夠安全,那么??的出現(xiàn)很好的解決了這個(gè)問(wèn)題。
合并空值運(yùn)算符 (a ?? b )如果可選項(xiàng) a 有值則展開,如果沒(méi)有值,是 nil ,則返回默認(rèn)值 b 。表達(dá)式 a 必須是一個(gè)可選類型。表達(dá)式 b 必須與 a 的儲(chǔ)存類型相同。
合并空值運(yùn)算符是下邊代碼的縮寫:

a != nil ? a! : b
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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