可選型Optional

Optional可選型

1.什么是可選型
2.為什么要有可選型
3.可選型的使用
4.可選型的本質(zhì)
5.?與!與??

什么是Optional

可選型(Optional)是Swift中的一種類型,或者稱之為一種類型的類別,用來指定某個實例可能沒有值,即要么有值并且可用,要么沒有值,即為nil.

  • 在swift中,只有一個實例對象是可選型才可以作為空值(nil),或者對其置空.
  • 任何一種類型都可以作為可選型,甚至是元組或者可選型本身.
  • swift不允許使用未進行初始化的變量,所以變量都沒有默認值,而只有可選型例外,它的默認值為nil

為什么要有可選型

程序開發(fā)中,多數(shù)語言都有nil的出現(xiàn),導(dǎo)致程序異常退出.所以我們經(jīng)常會做各種各樣的判斷,來避免對一個空值進行非法訪問.
在C語言中,經(jīng)常用-1來表示一個操作失敗,Objective-c中查找字符串的內(nèi)容使用了NSNotFound(本質(zhì)是一個最大的數(shù))來表示未查找到.稱這些值為一個哨兵也不為過(Swift進階).
舉例說明:

    NSString *string = nil;
    if( [string rangeOfString:@"a"].location != NSNotFound){
        NSLog(@"contain");
    }else{
        NSLog(@"not contain");
    }
    
執(zhí)行打印結(jié)果為"contain"
因為在Objective-c中,我們對一個nil發(fā)送消息,是安全的什么也不會發(fā)生.如果消息返回一個對象,那么nil會被返回,如果是數(shù)值類型,那么返回0,如果是結(jié)構(gòu)體,那么它的值都會被初始化為0.所以哨崗值很容易導(dǎo)致無法預(yù)期的錯誤.
Swift號稱是更加安全的語言,當(dāng)然一部分來自于可選型的加入,一個實例沒有被聲明為可空類型,它就不可能是nil;通過這種方式啦鸣,編譯器知道一個實例是否可能為nil 。這種顯式聲明可以讓代碼更具表達能力蟹漓,也更安全.   

可選型的使用

聲明一個可選型使用?或者!緊跟類型后面,不可以有空格

    var option:Int?  = "abc"
    option = nil

!表示為隱式可選型,在后面會進行敘述.
使用可選型的值我們需要對其進行解包,解開的方式也有很多種

  • if判斷
  • 隱式解包
  • 強制解包
  • 可選綁定
  • ??空合運算符
//1.
if option != nil{
   //do something
}

//2.?
//如果值為nil將什么也不發(fā)生
option?var

//3. !當(dāng)為nil,會導(dǎo)致程序異常退出
option!

可選綁定

optional binding是一種固定模式攀涵,對于判斷可空實例是否有值很有用访敌。如果有值,就將其賦給一個臨時常量或變量弧岳,并且使這個常量或變量在條件語句的第一個分支代碼中可用轿曙。這樣可以讓代碼更簡潔,同時保持表達力韵丑。

if let value = optional{
    //有值  do some
    }else{
    //沒有值nil
}

當(dāng)然可選實例綁定可以進行嵌套,當(dāng)遇到多個可選型,嵌套可空實例綁定可能會顯得錯綜復(fù)雜。就像是金字塔一樣,所以單個if let綁定就可以展開多個可空實例.
可空鏈式調(diào)用 (optional chaining)提供了一種對可空實例進行查詢以判斷其是否包含值的機制虚缎。兩者的一個重要區(qū)別是撵彻,可空鏈式調(diào)用允許程序員把多個查詢串聯(lián)為一個可空實例的值。如果鏈式調(diào)用中的每個可空實例都包含值实牡,那么每個調(diào)用都會成功陌僵,整個查詢鏈會返回期望類型的可空實例

if let error = errorStr{
   if let code = Int(error){
    //......
    }
}

//更優(yōu)雅
if let error = errorStr,code = Int(error){
   //.....
}

當(dāng)然也可以使用guard,while(不常用).guard語句的Optional綁定與if語句類似,區(qū)別有兩個创坞,一個就是guard語句與if語句本身的語義區(qū)別碗短;還有一個是guard語句中聲明的對象是處于guard語句所在的作用域的,而不僅限于guard語句塊作用域题涨。所以guard語句的Optional綁定在實際項目中可能會用得更多些偎谁,因為它更加便利「俣拢可將其聲明的拆解掉Optional的對象將之前所聲明的Optional對象標識給完全覆蓋掉巡雨。

var a = Int?(0)
//覆蓋同名變量
guard let a = a else{
   return
}
a += 10

可選型的本質(zhì)

可選型實際是一個泛型枚舉,遵循ExpressibleByNilLiteral協(xié)議(nil字面量),我們可以顯示的聲明一個Optional.

var website: Optional<String> = Optional.some("www.baidu.com")
print(website)

website = Optional.none
print(website)

當(dāng)然也可以點擊查看其聲明

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
.....
}

?與!與??

?

?語法糖其實就是簡化了聲明和賦值

var optional:Optional<Int>
//等同于var optional:Int?
//賦值時 等同于optional = nil
optional = Optional<Int>.none
optional = Optional<Int>.some(5)
//等同于optional = 5

在聲明或者賦值一個Optional的變量時,?語法糖做的事情就是聲明一個Optional<T>席函,然后查看等號右邊是不是nil這個標記值铐望。如果不是,則使用 init(_ some: T)用等號右邊的類型T的值生成一個 .some枚舉并賦值給這個Optional 變量,如果是nil茂附,將其賦為none枚舉正蛙。
? 放在某個Optional 變量后面,表示對這個變量進行判斷营曼,并且隱式地unwrap

optional?.distance(to: 10)
//相當(dāng)于
if let value = optional{
value.distance(to: 10)
}

更存在價值的地方在于可以鏈式調(diào)用乒验,也就是所謂的 Optional Chaining,這樣可以避免一大堆的條件分支蒂阱,而使代碼變得易讀簡潔徊件。
? 放在某個 optional 的 protocol (Objective-C)方法的括號前面奸攻,以表示詢問是否可以對該方法調(diào)用

!

! 放在Optional變量的后面,表示強制的 unwrap 轉(zhuǎn)換:
使一個 Optional<T> 的量被轉(zhuǎn)換為 T虱痕。特別注意睹耐,如果這個 Optional 的量是 nil 的話,這種轉(zhuǎn)換會在運行時讓程序崩潰.

func !<T>(value:Optional<T>) -> T{
switch value{
     case .none:
     fatalError("error:nil")
     case .some(v):
     return v
   }
}

!放在類型后面,隱式解析可選類型,表示強制的隱式轉(zhuǎn)換部翘。是一個類型聲明的語法糖硝训。?聲明的是Optional,而!其實聲明的是一個ImplicitlyUnwrappedOptional(deprecated)類型新思。會在使用的時候自動地去unwrap窖梁,繼續(xù)之后的操作調(diào)用,而不必去增加一次手動的顯示/隱式操作夹囚。隱式解析可選類型依然是一個可選類型纵刘,可選類型的特性它同樣適用,只是注意荸哟,當(dāng)隱式解析可選項值為 nil 的時候解析取值假哎,會運行出錯。如果一個變量之后可能變成nil的話請不要使用隱式解析可選類型鞍历。如果你需要在變量的生命周期中判斷是否是nil的話舵抹,請使用普通可選類型。

??nil-coalescing operation 空和運算符

??提供一個默認值,當(dāng)一個可選型為nil時,使用該值,否則就是其解包后的值

var optional:Int? = nil
optional ?? 5

覺得似曾相識,跟三目運算符差不多,用三目運算符可以對其改寫即optional != nil ? optional! : 5,那么他和三目運算一樣嗎?肯定不一樣,如果?前面后面是一個比較耗時繁瑣的操作,那么效率就會很差.
我們可以在可選型的定義中查看該操作符的定義.

public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T

至于這里為什么使用了自動閉包,我們可以大致實現(xiàn)其邏輯,使用了閉包我們就可以達到短路的效果,當(dāng)值不是nil時,避免不必要的計算.

public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T{
if let value = optional{
       return value
   }else{
       return defaultValue()
   }
}

??用于聲明類型或者更多個???....

當(dāng)聲明一個變量做類型標注時可能會遇到多個??,其實就是嵌套可選型,需要我們進行多次解包,就好像盒子里面又是一個盒子..

let number: Int??? = 10
print(number)
// Optional(Optional(Optional(10)))

解包也有多種方式


let number: Int??? = 10

//暴力拆解型
print(number!!!)

//嵌套地獄型
if let number = number {
if let number = number {
if let number = number {
print(number)
}
}
}

//可選綁定
if let n1 = number,
let n2 = n1,
let n3 = n2 {
print(n3)
}

func printNumber(_ number: Int???) {
guard let n1 = number, let n2 = n1, let n3 = n2 else {
return
}
print(n3)
}

參考鏈接

聊聊swift語言中的“??”
行走于 Swift 的世界中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劣砍,一起剝皮案震驚了整個濱河市惧蛹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刑枝,老刑警劉巖香嗓,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異装畅,居然都是意外死亡陶缺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門洁灵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饱岸,“玉大人,你說我怎么就攤上這事徽千∩环眩” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵双抽,是天一觀的道長百框。 經(jīng)常有香客問我,道長牍汹,這世上最難降的妖魔是什么铐维? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任柬泽,我火速辦了婚禮,結(jié)果婚禮上嫁蛇,老公的妹妹穿的比我還像新娘锨并。我一直安慰自己,他們只是感情好睬棚,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布第煮。 她就那樣靜靜地躺著,像睡著了一般抑党。 火紅的嫁衣襯著肌膚如雪包警。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天底靠,我揣著相機與錄音害晦,去河邊找鬼。 笑死暑中,一個胖子當(dāng)著我的面吹牛壹瘟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播痒芝,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼牵素!你這毒婦竟也來了严衬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤笆呆,失蹤者是張志新(化名)和其女友劉穎请琳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赠幕,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡俄精,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了榕堰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竖慧。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逆屡,靈堂內(nèi)的尸體忽然破棺而出圾旨,到底是詐尸還是另有隱情,我是刑警寧澤魏蔗,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布砍的,位于F島的核電站,受9級特大地震影響莺治,放射性物質(zhì)發(fā)生泄漏廓鞠。R本人自食惡果不足惜帚稠,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望床佳。 院中可真熱鬧滋早,春花似錦、人聲如沸夕土。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怨绣。三九已至角溃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篮撑,已是汗流浹背减细。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赢笨,地道東北人未蝌。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像茧妒,于是被迫代替她去往敵國和親萧吠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355