Swift進階10:可選類型Optional & Equatable+Comparable協(xié)議

Optional分析

Swift中的可選類型(Optional),用于處理值缺失的情況吩抓,有以下兩種情況

  • 有值,且等于x
  • 沒有值

這點可以通過Swift源碼->Optional.swift源碼(CMD+P,搜索Optional)源碼來印證

@frozen
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
    ......
  //為nil
  case none

    ......
  //有值
  case some(Wrapped)
  
  ......
}
  • 通過源碼可知涨椒,Optional的本質(zhì)是enum,當(dāng)前枚舉接收一個泛型參數(shù)Wrapped烫扼,當(dāng)前Some的關(guān)聯(lián)值就是當(dāng)前的Wrapper彤敛,下面兩種寫法完全等價
var age: Int? = 10
等價于
var age1: Optional<Int> = Optional(10)

Optional使用模式匹配

  • 【Optional使用模式匹配】:既然Optional的本質(zhì)是枚舉,那么也可以使用模式匹配來匹配對應(yīng)的值卖词,如下所示
//1巩那、聲明一個可選類型的變量
var age: Int? = nil
//2、通過模式匹配來匹配對應(yīng)的值
switch age {
    case nil:
        print("age 是個空值")
    case .some(let val):
        print("age的值是\(val)")
}

Optional解包

【Optional解包】:因為是Optional類型此蜈,當(dāng)我們需要從其中拿到我們想要的值時即横,需要對其進行解包,因為當(dāng)前的可選項是對值做了一層包裝的裆赵,有以下兩種方式:

  • 1东囚、強制解包:好處是省事,壞處是一旦解包的值是nil战授,那么程序就會崩潰
image
  • 2页藻、通過可選項綁定:判斷當(dāng)前的可選項是否有值
    • if let:如果有值,則會進入if流程
    • guard let:如果為nil植兰,則會進入else流程
//可選項解包
var age: Int? = 10
//強制解包
print(age!)

//if let 可選綁定
if let value = age {
    print(value)
}

//guard let 可選綁定
guard let tmp = age else {
    print("age值為nil")
    return
}
print(tmp)

可選項綁定總結(jié)

  • 1份帐、使用if let創(chuàng)建的內(nèi)容當(dāng)中value僅僅只能在當(dāng)前if分支的大括號內(nèi)訪問
  • 2、使用guard let定義的tmp在當(dāng)前大括號外部也是能訪問的

unsafelyUnwrapped

這個和強制解包的內(nèi)容是一致的楣导,如下所示

//unsafelyUnwrapped 和強制解包內(nèi)容是一致的
var age: Int? = 30
print(age!)
print(age.unsafelyUnwrapped)

//如果age1是nil
var age1: Int? = nil
//print(age1!)
print(age1.unsafelyUnwrapped)

age1nil的結(jié)果和強制解包一致废境,程序會崩潰

image

  • 官方對其的描述如下
image

這里的-O,是指target -> Build Setting -> Optimization Level設(shè)置成-O時筒繁,如果使用的是age1.unsafelyUnwrapped噩凹,則不檢查這個變量是否為nil,

  • 1膝晾、設(shè)置Optimization LevelFastest, Smallest[-Os]
  • 2栓始、edit Scheme -> Run -> Info -> Build Configuration改為release模式,然后再次運行發(fā)現(xiàn)血当,沒有崩潰幻赚,與官方所說是一致的
image

Equatable協(xié)議

在下面的例子中禀忆,可以通過==判斷兩個可選項是否相等,原因是因為Optinal在底層遵循了Equatable協(xié)議

//Equatable協(xié)議
var age: Int? = 10
var age1: Optional<Int> = Optional(10)

age == age1
  • 繼續(xù)回到Optional源碼中落恼,可以看到Optional遵循了Equatable協(xié)議
extension Optional: Equatable where Wrapped: Equatable {
    
    ......
    
    @inlinable
  public static func ==(lhs: Wrapped?, rhs: Wrapped?) -> Bool {
    switch (lhs, rhs) {
    case let (l?, r?):
      return l == r
    case (nil, nil):
      return true
    default:
      return false
    }
  }
}

Swift標(biāo)準(zhǔn)庫中的類型

在Swift中的類型箩退,可以通過遵循Equatable協(xié)議來使用相等運算符(==)不等運算符(!=)比較兩個值相等還是不相等,Swift標(biāo)準(zhǔn)庫中絕大多數(shù)類型都默認實現(xiàn)了Equatable協(xié)議

例如下面的例子佳谦,對于Int類型來說戴涝,系統(tǒng)默認實現(xiàn)了 ==

image

結(jié)構(gòu)體類型

對于自定義的類型,如果想實現(xiàn) ==钻蔑,應(yīng)該怎么辦呢啥刻?

  • 如果像下面這樣寫,是會直接報錯的
image
  • 可以通過遵循Equatable協(xié)議實現(xiàn)咪笑,如下所示
image

為什么呢可帽?其根本原因是因為遵守了Equatable協(xié)議,系統(tǒng)默認幫我們實現(xiàn)了==方法

  • 查看SIL文件
image
  • 查看__derived_struct_equals方法的實現(xiàn)
image

image

Class類型

如果像Struct那么寫窗怒,會報錯映跟,提示需要自己實現(xiàn)Equatable協(xié)議的方法

image

  • class中手動實現(xiàn)Equatable協(xié)議的方法
//class實現(xiàn)Equatable協(xié)議
class HTTeacher: Equatable {
    var age: Int
    var name: String
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    static func == (lhs: HTTeacher, rhs: HTTeacher) -> Bool {
        return lhs.age == rhs.age && lhs.name == rhs.name
    }
}
var t1 = HTTeacher.init(age: 18, name: "name")
var t2 = HTTeacher.init(age: 19, name: "name")
print(t1 == t2)

區(qū)分 == vs ===

  • == 相當(dāng)于 equal to,用于判斷兩個值是否相等
  • === 是用來判斷 兩個對象是否是同一個實例對象(即內(nèi)存地址指向是否一致)

Comparable協(xié)議

除了Equatable扬虚,還有Comparable協(xié)議,其中的運算符有:< 努隙、<=、>=辜昵、> 荸镊、...、..<

public protocol Comparable : Equatable {
    static func < (lhs: Self, rhs: Self) -> Bool
    
    static func <= (lhs: Self, rhs: Self) -> Bool
    
    static func >= (lhs: Self, rhs: Self) -> Bool
    
    static func > (lhs: Self, rhs: Self) -> Bool
}
extension Comparable {
    public static func ... (minimum: Self, maximum: Self) -> ClosedRange<Self>
    ......
}

Struct重載 < 運算符

  • struct為例路鹰,遵循Comparable協(xié)議,重寫 < 運算符
image

?? 空運算符

如果當(dāng)前的變量為nil贷洲,可以在??返回一個nil時的默認值

  • 下面例子的打印結(jié)果是什么?
//?? 空運算符
var age: Int? = nil
//?? 等價于 if let / guard let
print(age ?? 20)

//---打印結(jié)果
//20
  • 進入Optional源碼,查看??實現(xiàn)
<!--返回T-->
@_transparent//空運算符
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
    rethrows -> T {
  switch optional {
  case .some(let value):
    return value
  case .none:
    return try defaultValue()
  }
}

<!--返回T?-->
@_transparent
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?)
    rethrows -> T? {
  switch optional {
  case .some(let value):
    return value
  case .none:
    return try defaultValue()
  }
}

從源碼中分析晋柱,??只有兩種類型优构,一種是T,一種是T?雁竞,主要是與 ?? 后面的返回值有關(guān)(即簡單來說钦椭,就是??后是什么類型,??返回的就是什么類型),如下所示

  • ??后面是age1碑诉,而age1的類型是Int?彪腔,所以t的類型是 Int?
image
  • 如果??20呢? 則 t的類型是Int
image
  • 如果??String呢? -- 會報錯,??要求類型一致(跟是否是可選類型無關(guān))
image

可選鏈

可選鏈 則意味著 允許在一個鏈上來訪問當(dāng)前的屬性/方法,如下所示

//可選鏈
class HTTeacher{
    var name: String?
    var subject: HTSubject?
}

class HTSubject {
    var subjectName: String?
    func test() { print("test") }
}

var s = HTSubject()
var t = HTTeacher()

//可選鏈訪問屬性
if let tmp = t.subject?.subjectName {
    print("tmp不為nil")
} else {
    print("tmp為nil")
}
//可選鏈訪問方法
t.subject?.test()

運行結(jié)果如下进栽,因為t.subject為nil德挣,所以屬性和方法都不會往下執(zhí)行

image

總結(jié)

  • Optional的本質(zhì)是enum,所以可以使用模式匹配來匹配Optional的值
  • Optional的解包方式有兩種:
    • 1快毛、強制解包:一旦為nil格嗅,程序會崩潰
    • 2番挺、可選值綁定if let (只能在if流程的作用域內(nèi)訪問)、guard let
  • Equatable協(xié)議:
    • 對于swift標(biāo)準(zhǔn)庫中的絕大部分類型都默認實現(xiàn)了Equatable協(xié)議
    • 對于自定義Struct類型屯掖,僅需要遵守Equatable協(xié)議
    • 對于自定義class類型玄柏,除了需要遵守Equatable協(xié)議,還需要自己實現(xiàn)Equatable協(xié)議的方法
  • 區(qū)分 == vs ===
    • == 相當(dāng)于 equal to贴铜,用于判斷兩個值是否相等
    • === 是用來判斷 兩個對象是否是同一個實例對象(即內(nèi)存地址指向是否一致)
  • Comparable協(xié)議:
    • 對于自定義類型粪摘,需要遵循Comparable協(xié)議,并重寫運算符
  • ??空運算符
    • ??只有兩種類型绍坝,一種是T徘意,一種是T?,主要是與 ?? 后面的返回值有關(guān)(即簡單來說陷嘴,就是??后是什么類型映砖,??返回的就是什么類型
  • 可選鏈:允許在一個鏈上來訪問當(dāng)前的屬性/方法间坐,如果為nil灾挨,則不會執(zhí)行?后的屬性/方法
  • unsafelyUnwrapped:與強制解包類似,但是如果項目中設(shè)置target -> Build Setting -> Optimization Level設(shè)置成-O時竹宋,如果使用的是age.unsafelyUnwrapped劳澄,則不檢查這個變量是否為nil
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜈七,隨后出現(xiàn)的幾起案子秒拔,更是在濱河造成了極大的恐慌,老刑警劉巖飒硅,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砂缩,死亡現(xiàn)場離奇詭異,居然都是意外死亡三娩,警方通過查閱死者的電腦和手機庵芭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雀监,“玉大人双吆,你說我怎么就攤上這事』崆埃” “怎么了好乐?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瓦宜。 經(jīng)常有香客問我蔚万,道長,這世上最難降的妖魔是什么临庇? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任反璃,我火速辦了婚禮区转,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘版扩。我一直安慰自己废离,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布礁芦。 她就那樣靜靜地躺著蜻韭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柿扣。 梳的紋絲不亂的頭發(fā)上肖方,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音未状,去河邊找鬼俯画。 笑死,一個胖子當(dāng)著我的面吹牛司草,可吹牛的內(nèi)容都是我干的艰垂。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼埋虹,長吁一口氣:“原來是場噩夢啊……” “哼猜憎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起搔课,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤胰柑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爬泥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柬讨,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年袍啡,在試婚紗的時候發(fā)現(xiàn)自己被綠了踩官。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡葬馋,死狀恐怖卖鲤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畴嘶,我是刑警寧澤蛋逾,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站窗悯,受9級特大地震影響区匣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一亏钩、第九天 我趴在偏房一處隱蔽的房頂上張望莲绰。 院中可真熱鬧,春花似錦姑丑、人聲如沸蛤签。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽震肮。三九已至,卻和暖如春留拾,著一層夾襖步出監(jiān)牢的瞬間戳晌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工痴柔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沦偎,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓咳蔚,卻偏偏與公主長得像豪嚎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子屹篓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

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