Swift之可選項(xiàng)

為了表示我對(duì)簡(jiǎn)書(shū)『飽醉豚』事件的不滿(mǎn),簡(jiǎn)書(shū)不再更新,后續(xù)有文章只更新 個(gè)人博客掘金

歡迎移步 個(gè)人博客
或者 掘金

本文首發(fā)于我的個(gè)人博客

定義

  • 可選項(xiàng),一般也叫可選類(lèi)型,它允許將值設(shè)置為nil
  • 在類(lèi)型名稱(chēng)后面加個(gè)問(wèn)號(hào)? 來(lái)定義一個(gè)可選項(xiàng)
var name: String? = "Jack"
name = nil


var age: Int? // 默認(rèn)就是nil 
age = 10
age = nil

強(qiáng)制解包

  • 可選項(xiàng)是對(duì)其他類(lèi)型的一層包裝,可以將它理解為一個(gè)盒子
  • 如果為nil,那么它是個(gè)空盒子
  • 如果不為nil,那么盒子里裝的是:被包裝類(lèi)型的數(shù)據(jù)
var age: Int? // 默認(rèn)就是nil 
age = 10
age = nil

  • 如果要從可選項(xiàng)中取出被包裝的數(shù)據(jù)(將盒子里裝的東西取出來(lái)),需要使用感嘆號(hào)! 進(jìn)行強(qiáng)制解包
var age: Int? = 10
let ageInt: Int = age!
ageInt += 10

  • 如果對(duì)值為nil的可選項(xiàng)(空盒子)進(jìn)行強(qiáng)制解包,將會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤
var age: Int?
age!// 報(bào)錯(cuò):Fatal error: Unexpectedly found nil while unwrapping an Optional value

判斷可選項(xiàng)是否包含值


let number = Int("123")
if number != nil {
    print("字符串轉(zhuǎn)換整數(shù)成功:\(number!)") 
} else {
    print("字符串轉(zhuǎn)換整數(shù)失敗") 
}

// 字符串轉(zhuǎn)換整數(shù)成功:123

可選項(xiàng)綁定

  • 可以使用可選項(xiàng)綁定來(lái)判斷可選項(xiàng)是否包含值
    • 如果包含就自動(dòng)解包,把值賦給一個(gè)臨時(shí)的常量(let)或者變量(var),并返回true,否則返回false
if let number = Int("123") {
   print("字符串轉(zhuǎn)換整數(shù)成功:\(number)") 
    // number是強(qiáng)制解包之后的Int值
    // number作用域僅限于這個(gè)大括號(hào)
} else { 
    print("字符串轉(zhuǎn)換整數(shù)失敗")
}


// 字符串轉(zhuǎn)換整數(shù)成功:123

eg:

enum Season : Int {
    case spring = 1, summer, autumn, winter
}
if let season = Season(rawValue: 6) {
    switch season { 
        case .spring:
            print("the season is spring")
        default:
            print("the season is other")
    }
} else {
    print("no such season")
}


// no such season

等價(jià)寫(xiě)法

可選項(xiàng)綁定中,如果多個(gè)條件比如下面


 if let first = Int("4") {
    if let second = Int("42") {
        if first < second && second < 100 {
            print("\(first) < \(second) < 100")
            } 
        }
}
// 4 < 42 < 100

可以用 , 分割開(kāi),看起來(lái)更簡(jiǎn)單

 if let first = Int("4"),
    let second = Int("42"),
    first < second && second < 100 {
    print("\(second) < \(second) < 100")
}
// 4 < 42 < 100

while循環(huán)中使用可選項(xiàng)綁定

  • 有如下需求
    //遍歷數(shù)組,將遇到的正數(shù)都加起來(lái),如果遇到負(fù)數(shù)或者非數(shù)字,停止遍歷
//遍歷數(shù)組,將遇到的正數(shù)都加起來(lái),如果遇到負(fù)數(shù)或者非數(shù)字,停止遍歷
// var strs = ["10", "20", "abc", "-20", "30"]

var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
    sum += num
    index += 1 
}
    
print(sum)

空合并運(yùn)算符 ??(Nil-Coalescing Operator)

eg:


public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
  • a ?? b
  • a 是可選項(xiàng)
  • b 是可選項(xiàng) 或者 不是可選項(xiàng)
  • b 跟 a 的存儲(chǔ)類(lèi)型必須相同
  • 如果 a 不為nil,就返回 a
  • 如果 a 為nil,就返回 b
  • 如果 b 不是可選項(xiàng),返回 a 時(shí)會(huì)自動(dòng)解包

規(guī)律: 返回的類(lèi)型取決于b

舉例如下:

let a: Int? = 1
let b: Int? = 2
let c = a ?? b // c是Int? , Optional(1)

let a: Int? = 1
let b: Int = 2
let c = a ?? b // c是Int , 1

let a: Int? = nil
let b: Int = 2
let c = a ?? b // c是Int , 2

let a: Int? = nil
let b: Int? = 2
let c = a ?? b // c是Int? , Optional(2)

let a: Int? = nil 
let b: Int = 2
// 如果不使用??運(yùn)算符 
let c: Int
if let tmp = a {
    c = tmp
} else { 
    c=b
}

// 使用 ?? 運(yùn)算符
let c = a ?? b // c是Int? , nil

多個(gè) ?? 一起使用


let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3 // c是Int , 1
let a: Int? = nil
let b: Int? = 2
let c = a ?? b ?? 3 // c是Int , 2
let a: Int? = nil
let b: Int? = nil
let c = a ?? b ?? 3 // c是Int , 3

??跟if let配合使用


let a: Int? = nil
let b: Int? = 2
if let c = a ?? b {
    print(c) 
}
// 類(lèi)似于if a != nil || b != nil

if let c = a, let d = b {
    print(c)
    print(d) 
}
// 類(lèi)似于if a != nil && b != nil

guard語(yǔ)句

  • 當(dāng)guard語(yǔ)句的條件為false時(shí),就會(huì)執(zhí)行大括號(hào)里面的代碼
  • 當(dāng)guard語(yǔ)句的條件為true時(shí),就會(huì)跳過(guò)guard語(yǔ)句
  • guard語(yǔ)句特別適合用來(lái)“提前退出”

guard 條件 else {
// do something....
退出當(dāng)前作用域
// return、break、continue、throw error }
  • 當(dāng)使用guard語(yǔ)句進(jìn)行可選項(xiàng)綁定時(shí),綁定的常量(let)、變量(var)也能在外層作用域中使用

假設(shè)我們有個(gè)登陸的需求,要求輸入賬號(hào),密碼。缺一不可。

用if語(yǔ)句書(shū)寫(xiě)

//if語(yǔ)句實(shí)現(xiàn)登陸
func login(_ info: [String : String]) { 
    let username: String
    if let tmp = info["username"] {
        username = tmp
    } else {
        print("請(qǐng)輸入用戶(hù)名")
        return
    }
    
    let password: String
    if let tmp = info["password"] {
        password = tmp
    } else {
        print("請(qǐng)輸入密碼")
        return
    }
    
    // 能來(lái)到這里,說(shuō)明,username和password都是有值的
    // if username ....
    // if password ....
    print("用戶(hù)名:\(username)", "密碼:\(password)", "登陸ing")
}
 
// 調(diào)用
login(["username" : "jack", "password" : "123456"]) // 用戶(hù)名:jack 密碼:123456 登陸ing 

login(["password" : "123456"]) // 請(qǐng)輸入密碼

login(["username" : "jack"]) // 請(qǐng)輸入用戶(hù)名

如果用guard來(lái)書(shū)寫(xiě)


func login(_ info: [String : String]) {
    guard let username = info["username"] else {
            print("請(qǐng)輸入用戶(hù)名")
            return
    }
    
    guard let password = info["password"] else {
            print("請(qǐng)輸入密碼")
            return
    }
    
    // if username ....
    // if password ....
    print("用戶(hù)名:\(username)", "密碼:\(password)", "登陸ing")
}

隱式解包(Implicitly Unwrapped Optional)

  • 在某些情況下,可選項(xiàng)一旦被設(shè)定值之后,就會(huì)一直擁有值
  • 在這種情況下,可以去掉檢查,也不必每次訪(fǎng)問(wèn)的時(shí)候都進(jìn)行解包,因?yàn)樗艽_定每次訪(fǎng)問(wèn)的時(shí)候都有值
  • 可以在類(lèi)型后面加個(gè)感嘆號(hào) ! 定義一個(gè)隱式解包的可選項(xiàng)

let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
    print(num1 + 6) // 16
}
if let num3 = num1 {
    print(num3) //10
}

注意不能設(shè)置為nil

let num1: Int! = nil
// Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
let num2: Int = num1

盡量不要使用這個(gè)強(qiáng)制解包。
除非你設(shè)計(jì)接口,不希望接收空值,如果別人傳Nil過(guò)來(lái),直接報(bào)錯(cuò)

字符串插值

  • 可選項(xiàng)在字符串插值或者直接打印時(shí),編譯器會(huì)發(fā)出警告

var age: Int? = 10
print("My age is \(age)")
  • 至少有3種方法消除警告
 print("My age is \(age!)")
// My age is 10

 print("My age is \(String(describing: age))")
// My age is Optional(10)

 print("My age is \(age ?? 0)")
// My age is 10

多重可選項(xiàng)

  • 可以使用lldb指令 frame variable –R 或者 fr v –R 查看區(qū)別
var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10


print(num2 == num3) // true

還有下面這種

var num1: Int? = nil
var num2: Int?? = num1
var num3: Int?? = nil


print(num2 == num3) // false
(num2 ?? 1) ?? 2 // 2
(num3 ?? 1) ?? 2 // 1

參考資料:

Swift官方源碼

從入門(mén)到精通Swift編程

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔,今天18年5月份再次想寫(xiě)文章,發(fā)現(xiàn)簡(jiǎn)書(shū)還為我保存起的...
    Jenaral閱讀 3,115評(píng)論 2 9
  • 1 掌握 理解可選項(xiàng)的概念要么有值,要么為 nil 知道可選項(xiàng)的規(guī)則參與計(jì)算前需要解包 知道兩個(gè)符號(hào) ?定義可選項(xiàng)...
    freemanIT閱讀 209評(píng)論 0 0
  • 基本介紹 Optional是swift的一大特色,也是swift初學(xué)者最容易困惑的問(wèn)題;定義變量時(shí),如果指定是可選...
    oh_flying閱讀 259評(píng)論 0 0
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說(shuō)明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 5,918評(píng)論 0 9
  • 基礎(chǔ)部分(The Basics) 當(dāng)推斷浮點(diǎn)數(shù)的類(lèi)型時(shí),Swift 總是會(huì)選擇Double而不是Float。 結(jié)合...
    gamper閱讀 1,487評(píng)論 0 7

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