Swift: 06-可選項(xiàng)

//可選項(xiàng) Optional
//可選項(xiàng),一般也叫可選類型坪郭,它允許將值設(shè)置為nil,默認(rèn)不允許設(shè)置為nil
//在類型名稱后面加個(gè)問(wèn)號(hào)患民? 來(lái)定義一個(gè)可選項(xiàng)
var str: String? = "123"
str = nil

var age: Int? //可選值默認(rèn)就是nil拼苍,var age:Int等價(jià)于var age:Int玖姑?= nil
age = 10
age = nil

var array = [1, 15, 40, 29]
func get(_ index:Int) -> Int? { //如果函數(shù)返回值可能為nil,返回值類型就要加社付?
    if index < 0 || index >= array.count {
        return nil
    } else {
        return array[index]
    }
}
print(get(1)) //Optional(15)
print(get(-1))//nil
print(get(4)) //nil

var age1:Int = 15
print(age1) //15

var age2:Int? = 15
print(age2) //Optional(15), 這個(gè)是可選類型


//強(qiáng)制解包(Forced Unwrapping)
//可選項(xiàng)是對(duì)其他類型的一層包裝,可以將它理解為一個(gè)盒子
//如果為nil邻耕,那么它是個(gè)空盒子
//如果不為nil鸥咖,那么盒子里面裝的是:被包裝類型的數(shù)據(jù)
var age3: Int? //默認(rèn)就是nil
age3 = 10
age3 = nil

把10賦值給age3,如圖相當(dāng)于Int10這個(gè)藍(lán)色的框框去掉
//如果要從可選項(xiàng)中取出被包裝的數(shù)據(jù)(將盒子里面裝的東西取出來(lái))兄世,需要使用啼辣!進(jìn)行強(qiáng)制解包
var age4: Int? = 10
var ageInt: Int = age4!
ageInt += 10

var age5: Int? = 10
var num = age5! + 20 //30
print(age5) //Optional(10)
//強(qiáng)制解包只是取值的過(guò)程,并不會(huì)修改age5本身的可選項(xiàng)值

//如果對(duì)值為nil的可選項(xiàng)(空盒子)進(jìn)行強(qiáng)制解包御滩,將會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤鸥拧,crash奔潰
//報(bào)錯(cuò)信息:Fatal error: Unexpectedly found nil while unwrapping an Optional value
var age6: Int?
//age6!  //這里會(huì)crash,報(bào)錯(cuò)先注釋掉了

//判斷可選項(xiàng)是否包含值
let number = Int("123")
if number != nil {
    print("字符串轉(zhuǎn)換成功:\(number!)") //這里的number可能轉(zhuǎn)換失敗削解,返回0或者-1都不合適富弦,只能返回nil,所以這種通過(guò)字符串轉(zhuǎn)換成Int類型氛驮,number是可選類型腕柜,需要強(qiáng)制解包
} else {
    print("字符串轉(zhuǎn)換整數(shù)失敗,返回nil")
}
// 字符串轉(zhuǎn)換整數(shù)成功:123
//var num = Int("xxx")


//可選項(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ù)失敗")
}

enum Season: Int {
    case spring = 1, summber, autumn, winter
}
//var sea = Season(rawValue: 2) 這里的sea是可選項(xiàng)蓖扑,因?yàn)楂@取枚舉傳入原始值唉铜,可能不存在對(duì)應(yīng)原始值的枚舉變量
if let season = Season(rawValue: 6) { //這里需要注意,可選項(xiàng)綁定會(huì)幫忙自動(dòng)解包律杠,獲取到的直接就是Season類型潭流,而不是Season?可選類型
    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ě)法
if let first = Int("4") {
    if let second = Int("42") {
        if first < second && second < 100 {
            print("\(first) < \(second) < 100")
        }
    }
}
//上面的寫(xiě)法等價(jià)于下面的寫(xiě)法:
if let first = Int("4"), //這里的可選項(xiàng)綁定柿赊,必須要使用, 逗號(hào)隔開(kāi)幻枉,不能直接使用&&符合拼接
    let second = Int("42"),
    first < second && second < 100 {
    
}

//while循環(huán)中使用可選項(xiàng)綁定
//遍歷數(shù)組碰声,將遇到的正數(shù)都加起來(lái),如果遇到負(fù)數(shù)或者非數(shù)字熬甫,停止遍歷
var strs = ["10", "20", "30", "abc", "-20", "30"]
var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
    sum += num
    index += 1
}
print(sum) //60 10+20+30=60


//空合并運(yùn)算符 ?? (Nil-Coalescing Operator)
//public func ?? <T>(optional:T?, defaultValue:@autoclosure () throws -> T?) rethrows -> T?
//
//public func ?? <T>(optional:T?, defaultValue:@autoclosure () throws -> T) rethrows -> T
//a ?? b
//1. 其中a必須是可選項(xiàng),
//2. b是可選項(xiàng) 或者不是可選項(xiàng)
//3. b和a的存儲(chǔ)類型必須相同
//4. 如果a 不為nil胰挑,就返回a
//5. 如果a 為nil,就返回b
//6. 如果b 不是可選項(xiàng)椿肩,返回a時(shí)自動(dòng)解包

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

let a1: Int? = nil
let b1: Int? = 2
let c1 = a1 ?? b1 //2

let a2: Int? = nil
let b2: Int? = nil
let c2 = a2 ?? b2 //nil

let a3: Int? = 1
let b3: Int = 2
let c3 = a3 ?? b3 //c是Int, 1

let a4: Int? = nil
let b4: Int = 2
let c4 = a4 ?? b4 //2

let a5: Int? = nil
let b5: Int = 2
//如果不使用?? 運(yùn)算符
let c5: Int
if let tmp = a5 { //可選項(xiàng)會(huì)綁定失敗
    c5 = tmp
} else {
    c5 = b5
}

//多個(gè)??一起使用
let a6: Int? = 1
let b6: Int? = 2
let c6 = a6 ?? b6 ?? 3 //c是Int瞻颂,1

let a7: Int? = nil
let b7: Int? = 2
let c7 = a7 ?? b7 ?? 3 //c7是Int,2

let a8: Int? = nil
let b8: Int? = nil
let c8 = a8 ?? b8 ?? 3 //c8是Int郑象,3

let a9: Int? = 1
let b9: Int? = 2
let c9 = a9 ?? 3 ?? b //c9是Int贡这,這種會(huì)警告,??左邊只能是可選項(xiàng)厂榛,不可以是Int

//??跟if let配合使用
let a10: Int? = nil
let b10: Int? = 2
if let c10 = a10 ?? b10{
    print(c10)
}
//類似于 if a != nil || b != nil, 并且可以自動(dòng)解包賦值給 c10
//類似這種會(huì)有多個(gè)可選項(xiàng)解包可以使用多個(gè) ?? 連接起來(lái)使用

if let c = a, let d = b {
    print(c)
    print(d)
}
//類似于 if a != nil && b != nil
//a自動(dòng)解包成功并且b自動(dòng)解包成功盖矫,if條件才滿足,且的關(guān)系

//if 語(yǔ)句實(shí)現(xiàn)登陸
func login(_ info: [String: String]) {
    var username: String
    if let tmp = info["username"] {
        username = tmp
    } else {
        username = ""
        print("請(qǐng)輸入用戶名")
        return
    }
    
    var password: String
    if let tmp = info["password"] {
        password = tmp
    } else {
        password = ""
        print("請(qǐng)輸入密碼")
        return
    }
    //if username...
    //if password...
    print("用戶名:\(username)","密碼:\(password)","登陸ing")
}

login(["username":"jack","password":"123456"]) //用戶名:jack 密碼:123456 登陸ing
login(["password":"123456"]) //請(qǐng)輸入用戶名
login(["username":"jack"]) //請(qǐng)輸入密碼

//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) “提前退出”
func test() {
    guard 1>2 else {
        //do something
        //一定要推出當(dāng)前作用域
        return
    }
}
//當(dāng)使用guard語(yǔ)句進(jìn)行可選項(xiàng)綁定時(shí),綁定的常量(let),變量(var)也能在外層作用域中使用

//前面登陸的代碼可以用guard來(lái)優(yōu)化下:

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


//隱式解包 (Implicitly Unwrapped Optional)
//某些情況下柜砾,可選項(xiàng)一旦被設(shè)定值之后湃望,就會(huì)一直擁有值
//這種情況下,可以去掉檢查痰驱,也不必每次訪問(wèn)的時(shí)候都進(jìn)行解包证芭,因?yàn)樗艽_定每次訪問(wèn)的時(shí)候都有值
//可以在類型后門加個(gè)感嘆號(hào)!定義一個(gè)隱式解包的可選項(xiàng)
let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
    print(num1 + 6)
}

if let num3 = num1 {
    print(num3)
}

//盡量不要使用担映!废士,大多數(shù)情況下使用?的可選項(xiàng)
let num4:Int! = nil //加了另萤!也是可選項(xiàng)湃密,只不過(guò)是隱式解包的可選項(xiàng)
//let num5:Int = num4
//這里會(huì)報(bào)錯(cuò):Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
//有一種情況,就是如果你希望別人傳給你的參數(shù)必須是Int值四敞,不能為nil泛源,如果為nil,就崩潰掉忿危,那就可以使用這種類型达箍,這種也是不合理,還是期望使用铺厨?缎玫。


//字符串插值
//可選項(xiàng)在字符串插值或者直接打印時(shí)硬纤,編譯器會(huì)發(fā)出警告
var age7: Int? = 10
print("my age is \(age7)") //my age is Optional(10)
//有三種方法可以消除警告
//1
print("my age is \(age7!)") //my age is 10
//2
print("my age is \(String(describing: age7))") //my age is Optional(10)
//3
print("my age is \(age7 ?? 0)") // my age is 10

//多重可選項(xiàng)
var num11: Int? = 10
var num22: Int?? = num11
var num33: Int?? = 10
print(num22 == num33) //true
image.png
var num111: Int? = nil
var num222: Int?? = num11
var num333: Int?? = nil

print(num222 == num333) //false
print(num111 == num333) //false

print((num222 ?? 1) ?? 2) //2
//這里(num222 ?? 1)強(qiáng)制解包之后是 num111,然后num111 ?? 2赃磨,因?yàn)閚um111 強(qiáng)制解包之后是nil筝家,所以最終輸入2
print((num333 ?? 1) ?? 2) //1
//這里 num333強(qiáng)值解包之后是nil,1 ?? 2邻辉,所以返回1
//可以使用lldb指令 frame variable -R 或者 fr v -R 查看區(qū)別
image.png
var num1: Int? = 10
var num2: Int?? = num1
var num3: Int?? = 10
image.png
var num1: Int? = nil
var num2: Int?? = num1
var num3: Int?? = nil
#這里有個(gè)注意點(diǎn)溪王,如果num = 后面有值才是有意義的,如果是none是沒(méi)有意義的
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末值骇,一起剝皮案震驚了整個(gè)濱河市莹菱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吱瘩,老刑警劉巖道伟,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異使碾,居然都是意外死亡蜜徽,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門部逮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)娜汁,“玉大人,你說(shuō)我怎么就攤上這事兄朋。” “怎么了怜械?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵颅和,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我缕允,道長(zhǎng)峡扩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任障本,我火速辦了婚禮教届,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘驾霜。我一直安慰自己案训,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布粪糙。 她就那樣靜靜地躺著强霎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蓉冈。 梳的紋絲不亂的頭發(fā)上城舞,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天轩触,我揣著相機(jī)與錄音,去河邊找鬼家夺。 笑死脱柱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拉馋。 我是一名探鬼主播榨为,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼椅邓!你這毒婦竟也來(lái)了柠逞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤景馁,失蹤者是張志新(化名)和其女友劉穎板壮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體合住,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绰精,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了透葛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笨使。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖僚害,靈堂內(nèi)的尸體忽然破棺而出硫椰,到底是詐尸還是另有隱情,我是刑警寧澤萨蚕,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布靶草,位于F島的核電站,受9級(jí)特大地震影響岳遥,放射性物質(zhì)發(fā)生泄漏奕翔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一浩蓉、第九天 我趴在偏房一處隱蔽的房頂上張望派继。 院中可真熱鬧,春花似錦捻艳、人聲如沸驾窟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纫普。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昨稼,已是汗流浹背节视。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留假栓,地道東北人寻行。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像匾荆,于是被迫代替她去往敵國(guó)和親拌蜘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容