swift枚举(三)-Optional

swift枚举(一)

swift枚举(二)

认识可选值

之前我们在写代码过程中早就接触过可选值,比如我们在代码中这样定义:

    class IFLPerson {
        var name: String?
    }

当前的name,我们就称之为可选值

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

这两种写法是等同的

nameOptional的本质是什么,我们直接跳转到 源码 打开 Optional.swift 文件

image.png

既然Optional本质是枚举,那么我们也可以实现一个自定义的Optional

比如给定任一自然数,如果自然数是奇数则返回,否则返回nil, 该如何设计

    enum IFLOptional<Value> {
        case some(Value)
        case none
    }
    
    func getOddValue(_ value: Int) -> IFLOptional<Int> {
        if value % 2 == 0 {
            return .none
        }
        return .some(value)
    }
    
    // 给定一个数组,删除数组中的所有奇数
    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)

结果

[2, 4, 6, 8]

如果我们把上面的 getOddValue 返回值更换一下,其实就和系统的Optional 使用没什么差别

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

其实就是利用当前编译器的类型检查来达到语法书写层面的安全性

当然如果每一个可选值都用模式匹配的方式来获取值,在代码书写上就比较繁琐,

我们还可以使用 if let 的方式来进行可选值绑定

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

还可以使用 guard let

如果 if let 凭空多了一个分支,guard let 是降低分支层次的办法

可选链

我们都知道在OC 中我们给一个nil 对象发送消息什么也不会发生

Swift中我们是没办法向一个nil对象直接发送消息的,但是借助可选链可以达到类似的效果

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

结果

Optional("ABC")

nil

再来看下面这段代码输出什么

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

结果

Optional("abc")

nil

同样的 可选链对于下标和函数调用 也适用

    var closure: ((Int) -> ())?
    closure?(1)     // closure为nil 不执行

closure为nil 不执行

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

结果

Optional(1)

nil

?? 运算符 (空合并运算符)

( a ?? b ) 将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回 一个默认值 b .

  • 表达式 a 必须是 Optional 类型
  • 默认值 b 的类型必须要和 a 存储值的类型保持一致

运算符重载

在源码中我们可以看到除了重载了 ?? 运算符,

Optional 类型还重载了 == , ?= 等 等运算符,实际开发中我们可以通过重载运算符简化我们的表达式

image.png

比如在开发中我们定义了一个二维向量,这个时候我们想对两个向量进行基本的操作,

那么我们就可以通过重载运算符来达到我们的目的

    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)

结果

Vector(x: 8, y: 14)

Vector(x: 2, y: 6)

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

隐士解析可选类型

隐式解析可选类型是可选类型的一种,使用的过程中和非可选类型无异

它们之间唯一 的区别是,隐式解析可选类型是你告诉 Swift 编译器,在运行时访问时,值不会 为 nil, 但是如果你导致nil值,运行报错

    var age: Int
    var age1: Int!
    age = nil       // 报错 'nil' cannot be assigned to type 'Int'
    age1 = nil
    var age: Int?
    var age1: Int!
    age = nil       // 改为可选值 就可以 赋值nil了
    age1 = nil

    let x = age1 % 2  // 这里不需要做解包的操作,编译器已经帮我们做了

其实日常开发中,我们比较常见的一种隐士可选类型

@IBOutlet weak var button: UIButton!

IBOutlet类型是Xcode强制为可选类型的,因为它不是在初始化时赋值的,而是在加载视图的时候

你可以把它设置为普通的可选类型,但是如果这个视图加载正确,它是不会为空的

与可选值有关的高阶函数

  • map : 这个方法接受一个闭包,如果可选值有内容则调用这个闭包进行转换
    var dict = ["one": "1", "two": "2"] 
    let result = dict["one"].map{ Int($0) } 
    print(result)

结果

Optional(Optional(1))

上面的代码中我们从字典中取出字符串”1”,并将其转换为Int类型,

但因为String转换成 Int不一定能成功,所以返回的是Int?类型,

而且字典通过键不一定能取得到值,所以map 返回的也是一个Optional,

所以最后上述代码result的类型为 Int?? 类型

那么如何把我们的双重可选展平开来,这个时候我们就需要使用到

  • flatMap: 可以把结果展平成为单个可选值
    var dict = ["one": "1", "two": "2"] 
    let result = dict["one"].flatMap{ Int($0) } 
    print(result)

结果

Optional(1)

  • 注意,这个方法是作用在Optional的方法,而不是作用在 Sequence上的
  • 作用在Sequence上的flatMap 在 Swift4.1 中被更名为 compactMap, 该方法可以将序列中的nil过滤出去
    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)

结果

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

[1, 2, 3]

元类型、AnyClass、Self (self)

  • AnyObject: 代表任意类的 instance,类的类型,仅类遵守的协议
  • Any: 代表任意类型,包括 funcation 类型或者 Optional 类型
  • AnyClass: 代表任意实例的类型
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容