Swift中的可選項(xiàng)Optional解包方式實(shí)現(xiàn)原理
為什么需要Optional
Swift中引入了可選項(xiàng)(Optional)的概念是為了解決在代碼中對(duì)于某些變量或常量可能為nil的情況進(jìn)行處理,從而減少了程序中的不確定性,使得程序更加穩(wěn)定和安全。
什么是Optional
在Swift中,可選項(xiàng)的類(lèi)型是使用?來(lái)表示的,例如String?即為一個(gè)可選的字符串類(lèi)型,表示這個(gè)變量或常量可能為nil。而對(duì)于不可選項(xiàng),則直接使用相應(yīng)類(lèi)型的名稱,例如String表示一個(gè)非可選的字符串類(lèi)型。
var str: String = nil var str1: String? = nil
Optional實(shí)現(xiàn)原理
Optional實(shí)際上是Swift語(yǔ)言中的一種枚舉類(lèi)型。在Swift中聲明Optional類(lèi)型時(shí),編譯器會(huì)自動(dòng)將其轉(zhuǎn)換成對(duì)應(yīng)的枚舉類(lèi)型,例如:
var optionalValue: Int? = 10 // 等價(jià)于: enum Optional<Int> { case none case some(Int) } var optionalValue: Optional<Int> = .some(10)
在上面的代碼中,我們聲明了一個(gè)Optional類(lèi)型的變量optionalValue,并將其初始化為10。實(shí)際上,編譯器會(huì)自動(dòng)將其轉(zhuǎn)換為對(duì)應(yīng)的枚舉類(lèi)型,即Optional枚舉類(lèi)型的.some(Int),其中的Int就是我們所聲明的可選類(lèi)型的關(guān)聯(lián)值。
當(dāng)我們?cè)谑褂肙ptional類(lèi)型的變量時(shí),可以通過(guò)判斷其枚舉值是.none還是.some來(lái)確定它是否為nil。如果是.none,表示該Optional值為空;如果是.some,就可以通過(guò)訪問(wèn)其關(guān)聯(lián)值獲取具體的數(shù)值。
Optional的源碼實(shí)現(xiàn)為:
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral { case none case some(Wrapped) }
- Optioanl其實(shí)是標(biāo)準(zhǔn)庫(kù)里的一個(gè)enum類(lèi)型
- 用標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)語(yǔ)言特性的典型
- Optional.none 就是nil
- Optional.some 就是包裝了實(shí)際的值
- 泛型屬性 unsafelyUnwrapped
- 理論上我們可以直接調(diào)用unsafelyUnwrapped獲取可選項(xiàng)的值
Optional的解包方式
1. 可選項(xiàng)綁定(Optional Binding)
使用 if let 或者 guard let 語(yǔ)句來(lái)判斷 Optional 變量是否有值,如果有值則解包,并將其賦值給一個(gè)非可選類(lèi)型的變量。
var optionalValue: Int? = 10 // 可選項(xiàng)綁定 if let value = optionalValue { print("Optional value is \(value)") } else { print("Optional value is nil") }
可選項(xiàng)綁定語(yǔ)句有兩個(gè)分支:if分支和else分支。如果 optionalValue 有值,if 分支就會(huì)被執(zhí)行,unwrappedValue 就會(huì)被賦值為 optionalValue 的值。否則,執(zhí)行 else 分支。
2. 強(qiáng)制解包(Forced Unwrapping)
使用!來(lái)獲取一個(gè)不存在的可選值會(huì)導(dǎo)致運(yùn)行錯(cuò)誤,在使用!強(qiáng)制展開(kāi)之前必須保證可選項(xiàng)中包含一個(gè)非nil的值
var optionalValue: Int? = 10 let nonOptionalValue = optionalValue! // 解包optionalValue值 print(nonOptionalValue) // 輸出:10
需要注意的是,如果 Optional 類(lèi)型的值為 nil,使用強(qiáng)制解包方式解包時(shí),會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤 (Runtime Error)。
3. 隱式解包(Implicitly Unwrapped Optionals)
在定義 Optional 類(lèi)型變量時(shí)使用 ! 操作符,標(biāo)明該變量可以被隱式解包。用于在一些情況下,我們可以確定該 Optional 變量綁定后不會(huì)為 nil,可以快捷的解包而不用每次都使用 ! 或者 if let 進(jìn)行解包。
var optionalValue: Int! = 10 let nonOptionalValue = optionalValue // 隱式解包 print(nonOptionalValue) // 輸出:10
需要注意的是,隱式解包的 Optional 如果 nil 的話,會(huì)導(dǎo)致 runtime error,所以使用隱式解包 Optional 需要確保其一直有值,否則還是需要檢查其非 nil 后再操作。
總的來(lái)說(shuō),我們應(yīng)該盡量避免使用強(qiáng)制解包,而是通過(guò)可選項(xiàng)綁定來(lái)處理 Optional 類(lèi)型的值,在需要使用隱式解包的情況下,也要確保其可靠性和穩(wěn)定性,盡量減少出現(xiàn)運(yùn)行時(shí)錯(cuò)誤的概率。
可選鏈(Optional Chaining)
是一種在 Optional 類(lèi)型值上進(jìn)行操作的方式,可以將多個(gè) Optional 值的處理放在一起,并在任何一個(gè) Optional 值為 nil 的時(shí)刻停止處理。
通過(guò)在 Optional 類(lèi)型值后面跟上問(wèn)號(hào) ?,我們就可以使用可選鏈來(lái)訪問(wèn)該 Optional 對(duì)象的屬性和方法。
class Person { var name: String var father: Person? init(name: String, father: Person?) { self.name = name self.father = father } } let father = Person(name: "Father", father: nil) let son = Person(name: "Son", father: father) // 可選鏈調(diào)用屬性 if let fatherName = son.father?.name { print("Father's name is \(fatherName)") // 輸出:Father's name is Father } else { print("Son without father") } // 可選鏈調(diào)用方法 if let count = son.father?.name.count { print("Father's name has \(count) characters") // 輸出:Father's name has 6 characters } else { print("Son without father") }
在上面的代碼中,我們定義了一個(gè) Person 類(lèi),并初始化了一個(gè)包含父親(father)的兒子(son)對(duì)象。其中,父親對(duì)象的father屬性為nil。我們使用問(wèn)號(hào) ? 來(lái)標(biāo)記 father 對(duì)象為 Optional 類(lèi)型,以避免訪問(wèn) nil 對(duì)象時(shí)的運(yùn)行時(shí)錯(cuò)誤。
需要注意的是,如果一個(gè) Optional 類(lèi)型的屬性通過(guò)可選鏈調(diào)用后,返回值不是 Optional 類(lèi)型,那么在可選鏈調(diào)用后,就不再需要加問(wèn)號(hào) ? 標(biāo)記其為 Optional 類(lèi)型了。
class Person { var name: String var age: Int? init(name: String, age: Int?) { self.name = name self.age = age } func printInfo() { print("\(name), \(age ?? 0) years old") } } let person = Person(name: "Tom", age: nil) // 可選鏈調(diào)用方法后,返回值不再是 Optional 類(lèi)型 let succeed = person.printInfo() // 輸出:Tom, 0 years old
在上面的代碼中,我們定義了一個(gè) Person 類(lèi),并初始化了一個(gè)包含年齡(age)的人(person)對(duì)象。在可選鏈調(diào)用對(duì)象的方法——printInfo() 方法后,因?yàn)樵摲椒ǚ祷刂挡皇?Optional 類(lèi)型,所以 returnedValue 就不再需要加問(wèn)號(hào) ? 標(biāo)記其為 Optional 類(lèi)型了。
Optional 的嵌套
將一個(gè) Optional 類(lèi)型的值作為另一個(gè) Optional 類(lèi)型的值的成員,形成嵌套的 Optional 類(lèi)型。
var optionalValue: Int? = 10 var nestedOptionalValue: Int?? = optionalValue
在上面的代碼中,我們定義了一個(gè) Optional 類(lèi)型的變量 optionalValue,并將其賦值為整型變量 10。然后,我們將 optionalValue 賦值給了另一個(gè) Optional 類(lèi)型的變量 nestedOptionalValue,形成了一個(gè)嵌套的 Optional 類(lèi)型。
在處理嵌套的 Optional 類(lèi)型時(shí),我們需要特別小心,因?yàn)樗鼈兊氖褂煤苋菀自斐蛇壿嬌系幕煜湾e(cuò)誤。為了解決這個(gè)問(wèn)題,我們可以使用 Optional Binding 或者 ?? 操作符(空合并運(yùn)算符)來(lái)降低 Optional 嵌套的復(fù)雜度。
var optionalValue: Int? = 10 var nestedOptionalValue: Int?? = optionalValue // 雙重可選項(xiàng)綁定 if let nestedValue = nestedOptionalValue, let value = nestedValue { print(value) // 輸出:10 } else { print("Optional is nil") } // 空合并運(yùn)算符 let nonOptionalValue = nestedOptionalValue ?? 0 print(nonOptionalValue) // 輸出:Optional(10)
在上面的代碼中,我們使用了雙重可選項(xiàng)綁定來(lái)判斷 nestedOptionalValue 是否可綁定,以及其嵌套的 Optional 值是否可綁定,并將該值賦值給變量 value,以避免 Optional 值的嵌套。另外,我們還可以使用 ?? 操作符(空合并運(yùn)算符)來(lái)對(duì)嵌套的 Optional 值進(jìn)行默認(rèn)取值的操作。
需要注意的是,雖然我們可以使用 ?? 操作符來(lái)降低 Optional 值的嵌套,但在具體的實(shí)際應(yīng)用中,我們應(yīng)該在設(shè)計(jì)時(shí)盡量避免 Optional 值的嵌套,以便代碼的可讀性和維護(hù)性。如果對(duì)于某個(gè)變量來(lái)說(shuō),它的值可能為空,我們可以考慮使用默認(rèn)值或者定義一個(gè)默認(rèn)值的 Optional 值來(lái)代替嵌套的 Optional 類(lèi)型。
學(xué)習(xí) Swift,勿忘初心,方得始終。但要陷入困境時(shí),也不要忘了最初的夢(mèng)想和時(shí)代所需要的技能。
以上就是Swift中的可選項(xiàng)Optional解包方式實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于Swift可選項(xiàng)Optional的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Swift實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01Swift利用指紋識(shí)別或面部識(shí)別為應(yīng)用添加私密保護(hù)功能
這篇文章主要給大家介紹了關(guān)于Swift利用指紋識(shí)別或面部識(shí)別為應(yīng)用添加私密保護(hù)功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友下面隨著小編來(lái)一起看看吧2018-05-05Swift?Package?技巧及混編兼容問(wèn)題詳解
這篇文章主要為大家介紹了Swift?Package?技巧及混編兼容問(wèn)題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Swift?并發(fā)修改Sendable?閉包實(shí)例詳解
這篇文章主要為大家介紹了Swift?并發(fā)修改Sendable?閉包實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10swift中正確安全聲明一個(gè)單例的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于swift中如何正確安全聲明一個(gè)單例的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Swift5中fileprivate與private的差別淺析
這篇文章主要給大家介紹了關(guān)于Swift5中fileprivate與private的差別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Swift5具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09