swift枚舉(三)-Optional

swift枚舉(一)

swift枚舉(二)

認(rèn)識(shí)可選值

之前我們?cè)趯懘a過(guò)程中早就接觸過(guò)可選值捡多,比如我們?cè)诖a中這樣定義:

    class IFLPerson {
        var name: String?
    }

當(dāng)前的name锁荔,我們就稱之為可選值

var name: String? == var name: Optional<String>

這兩種寫法是等同的

nameOptional的本質(zhì)是什么吵瞻,我們直接跳轉(zhuǎn)到 源碼 打開(kāi) Optional.swift 文件

image.png

既然Optional本質(zhì)是枚舉,那么我們也可以實(shí)現(xiàn)一個(gè)自定義的Optional

比如給定任一自然數(shù)嗤军,如果自然數(shù)是奇數(shù)則返回,否則返回nil, 該如何設(shè)計(jì)

    enum IFLOptional<Value> {
        case some(Value)
        case none
    }
    
    func getOddValue(_ value: Int) -> IFLOptional<Int> {
        if value % 2 == 0 {
            return .none
        }
        return .some(value)
    }
    
    // 給定一個(gè)數(shù)組,刪除數(shù)組中的所有奇數(shù)
    var array = [1, 2, 3, 4, 5, 6, 7, 8, 101]
    for elem in array {
        let value = getOddValue(elem)
        switch value {
        case let .some(value):
            array.remove(at: array.firstIndex(of: value)!)
        case .none:
            print("\(value) not exist")
        }
    }
    
    print("-------------")
    print(array)

結(jié)果

[2, 4, 6, 8]

如果我們把上面的 getOddValue 返回值更換一下细睡,其實(shí)就和系統(tǒng)的Optional 使用沒(méi)什么差別

    func getOddValue(_ value: Int) -> Int? {
        if value % 2 == 0 {
            return .none
        }
        return .some(value)
    }

其實(shí)就是利用當(dāng)前編譯器的類型檢查來(lái)達(dá)到語(yǔ)法書寫層面的安全性

當(dāng)然如果每一個(gè)可選值都用模式匹配的方式來(lái)獲取值叹哭,在代碼書寫上就比較繁瑣忍宋,

我們還可以使用 if let 的方式來(lái)進(jìn)行可選值綁定

    if let value = value {
        array.remove(at: array.firstIndex(of: value))
    }

還可以使用 guard let

如果 if let 憑空多了一個(gè)分支,guard let 是降低分支層次的辦法

可選鏈

我們都知道在OC 中我們給一個(gè)nil 對(duì)象發(fā)送消息什么也不會(huì)發(fā)生

Swift中我們是沒(méi)辦法向一個(gè)nil對(duì)象直接發(fā)送消息的风罩,但是借助可選鏈可以達(dá)到類似的效果

    let str: String? = "abc"
    let upperStr = str?.uppercased() // Optional<"ABC">
    var str1: String?
    let upperStr1 = str1?.uppercased() // nil
    print(upperStr)
    print(upperStr1)

結(jié)果

Optional("ABC")

nil

再來(lái)看下面這段代碼輸出什么

    let str: String? = "aBc"
    let lowerStr = str?.uppercased().lowercased()
    var str1: String?
    let lowerStr1 = str1?.uppercased().lowercased()
    print(lowerStr)
    print(lowerStr1)

結(jié)果

Optional("abc")

nil

同樣的 可選鏈對(duì)于下標(biāo)和函數(shù)調(diào)用 也適用

    var closure: ((Int) -> ())?
    closure?(1)     // closure為nil 不執(zhí)行

closure為nil 不執(zhí)行

    let dict: [String: Any]? = ["key1": 1, "key2": 2]
    print(dict?["key1"])
    print(dict?["key3"])

結(jié)果

Optional(1)

nil

?? 運(yùn)算符 (空合并運(yùn)算符)

( a ?? b ) 將對(duì)可選類型 a 進(jìn)行空判斷糠排,如果 a 包含一個(gè)值就進(jìn)行解包,否則就返回 一個(gè)默認(rèn)值 b .

  • 表達(dá)式 a 必須是 Optional 類型
  • 默認(rèn)值 b 的類型必須要和 a 存儲(chǔ)值的類型保持一致

運(yùn)算符重載

在源碼中我們可以看到除了重載了 ?? 運(yùn)算符超升,

Optional 類型還重載了 == , ?= 等 等運(yùn)算符入宦,實(shí)際開(kāi)發(fā)中我們可以通過(guò)重載運(yùn)算符簡(jiǎn)化我們的表達(dá)式

image.png

比如在開(kāi)發(fā)中我們定義了一個(gè)二維向量,這個(gè)時(shí)候我們想對(duì)兩個(gè)向量進(jìn)行基本的操作室琢,

那么我們就可以通過(guò)重載運(yùn)算符來(lái)達(dá)到我們的目的

    struct Vector {
    
        let x: Int
        let y: Int
    }
    extension Vector {
        static func + (firstVector: Vector, secondVector: Vector) -> Vector {
            return Vector(x: firstVector.x + secondVector.x, y: firstVector.y + secondVector.y)
        }
        static prefix func - (vector: Vector) -> Vector {
            return Vector(x: -vector.x, y: -vector.y)
        }
        static func - (firstVector: Vector, secondVector: Vector) -> Vector {
            return firstVector + -secondVector
        }
    }
    
    let v1 = Vector(x: 5, y: 10)
    let v2 = Vector(x: 3, y: 4)
    let v3 = v1 + v2
    let v4 = v1 - v2
    let v5 = -v1
    print(v3)
    print(v4)
    print(v5)

結(jié)果

Vector(x: 8, y: 14)

Vector(x: 2, y: 6)

Vector(x: -5, y: -10)

隱士解析可選類型

隱式解析可選類型是可選類型的一種乾闰,使用的過(guò)程中和非可選類型無(wú)異

它們之間唯一 的區(qū)別是,隱式解析可選類型是你告訴 Swift 編譯器盈滴,在運(yùn)行時(shí)訪問(wèn)時(shí)涯肩,值不會(huì) 為 nil, 但是如果你導(dǎo)致nil值,運(yùn)行報(bào)錯(cuò)

    var age: Int
    var age1: Int!
    age = nil       // 報(bào)錯(cuò) 'nil' cannot be assigned to type 'Int'
    age1 = nil
    var age: Int巢钓?
    var age1: Int!
    age = nil       // 改為可選值 就可以 賦值nil了
    age1 = nil

    let x = age1 % 2  // 這里不需要做解包的操作病苗,編譯器已經(jīng)幫我們做了

其實(shí)日常開(kāi)發(fā)中,我們比較常見(jiàn)的一種隱士可選類型

@IBOutlet weak var button: UIButton!

IBOutlet類型是Xcode強(qiáng)制為可選類型的竿报,因?yàn)樗皇窃诔跏蓟瘯r(shí)賦值的铅乡,而是在加載視圖的時(shí)候

你可以把它設(shè)置為普通的可選類型,但是如果這個(gè)視圖加載正確烈菌,它是不會(huì)為空的

與可選值有關(guān)的高階函數(shù)

  • map : 這個(gè)方法接受一個(gè)閉包阵幸,如果可選值有內(nèi)容則調(diào)用這個(gè)閉包進(jìn)行轉(zhuǎn)換
    var dict = ["one": "1", "two": "2"] 
    let result = dict["one"].map{ Int($0) } 
    print(result)

結(jié)果

Optional(Optional(1))

上面的代碼中我們從字典中取出字符串”1”花履,并將其轉(zhuǎn)換為Int類型,

但因?yàn)镾tring轉(zhuǎn)換成 Int不一定能成功挚赊,所以返回的是Int?類型诡壁,

而且字典通過(guò)鍵不一定能取得到值,所以map 返回的也是一個(gè)Optional荠割,

所以最后上述代碼result的類型為 Int?? 類型

那么如何把我們的雙重可選展平開(kāi)來(lái)妹卿,這個(gè)時(shí)候我們就需要使用到

  • flatMap: 可以把結(jié)果展平成為單個(gè)可選值
    var dict = ["one": "1", "two": "2"] 
    let result = dict["one"].flatMap{ Int($0) } 
    print(result)

結(jié)果

Optional(1)

  • 注意,這個(gè)方法是作用在Optional的方法蔑鹦,而不是作用在 Sequence上的
  • 作用在Sequence上的flatMap 在 Swift4.1 中被更名為 compactMap, 該方法可以將序列中的nil過(guò)濾出去
    let array1 = ["1", "2", "3", nil]
    let result2 = array1.compactMap {
        $0
    }
    print(result2)
    
    let array2 = ["1", "2", "3", "four"]
    let result3 = array2.compactMap {
        Int($0)
    }
    print(result3)

結(jié)果

["1", "2", "3"]

[1, 2, 3]

元類型夺克、AnyClass、Self (self)

  • AnyObject: 代表任意類的 instance嚎朽,類的類型铺纽,僅類遵守的協(xié)議
  • Any: 代表任意類型,包括 funcation 類型或者 Optional 類型
  • AnyClass: 代表任意實(shí)例的類型
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哟忍,一起剝皮案震驚了整個(gè)濱河市狡门,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锅很,老刑警劉巖其馏,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異爆安,居然都是意外死亡叛复,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鹏控,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)致扯,“玉大人,你說(shuō)我怎么就攤上這事当辐《督” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵缘揪,是天一觀的道長(zhǎng)耍群。 經(jīng)常有香客問(wèn)我,道長(zhǎng)找筝,這世上最難降的妖魔是什么蹈垢? 我笑而不...
    開(kāi)封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮袖裕,結(jié)果婚禮上曹抬,老公的妹妹穿的比我還像新娘。我一直安慰自己急鳄,他們只是感情好谤民,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布堰酿。 她就那樣靜靜地躺著,像睡著了一般张足。 火紅的嫁衣襯著肌膚如雪触创。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天为牍,我揣著相機(jī)與錄音哼绑,去河邊找鬼。 笑死碉咆,一個(gè)胖子當(dāng)著我的面吹牛抖韩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疫铜,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼帽蝶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了块攒?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤佃乘,失蹤者是張志新(化名)和其女友劉穎囱井,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體趣避,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庞呕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了程帕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片住练。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖愁拭,靈堂內(nèi)的尸體忽然破棺而出讲逛,到底是詐尸還是另有隱情,我是刑警寧澤岭埠,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布盏混,位于F島的核電站,受9級(jí)特大地震影響惜论,放射性物質(zhì)發(fā)生泄漏许赃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一馆类、第九天 我趴在偏房一處隱蔽的房頂上張望混聊。 院中可真熱鬧,春花似錦乾巧、人聲如沸句喜。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)藤滥。三九已至鳖粟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拙绊,已是汗流浹背向图。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留标沪,地道東北人榄攀。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像金句,于是被迫代替她去往敵國(guó)和親檩赢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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