11. 可选类型-Optional

157 阅读2分钟

一、可选类型

1. 定义

可选类型用来表示可能为空的情况,比如这样:

var a: Int? = nil
a = 3
print(a)

/* 执行结果
Optional(3)
Program ended with exit code: 0
*/

从执行结果上可以看到a的值是Optional(3),而非3。那么Optional的本质是什么?

2. 本质

这里我们直接在源码中查看Optional.swift

image-20220113153321994

image-20220113155658108

从这里可以看出Optional的本质就是枚举,初始化一个可选类型时,如果是nil就是创建Optional.none,否则就创建Optional.some的关联值。其实查看源码我们还可以看到一些运算符重载的方法,比如常见的可选类型取值方式let b = a ?? 0中的空合并运算符??在源码中它是这样的:

image-20220113154824879

从这里可以看到??其实就是对枚举值进行模式匹配。除了运算符重载,还可以看到高阶函数相关的方法:

image-20220113155453257

image-20220113155621660

从这里可以看出高阶函数其实都是先对枚举值进行模式匹配,none就不处理,some则执行闭包。接下来我们参照源码,仿写一个简单的可选类型。

二、仿写可选类型

1. 案例代码

这里我们直接添加代码:

import Foundation

enum MyOptional<T> {
    case none
    case some(T)

    init(_ value: T) {
        self = .some(value)
    }

    init() {
        self = .none
    }
}

var a: MyOptional<Int> = MyOptional()
a = MyOptional(3)
print(a)

/* 执行结果
some(3)
Program ended with exit code: 0
*/

这就是简单的可选类型,接下来我们给它增加个类似空合并运算符的效果。

2. 运算符重载

这里直接在拓展中添加代码:

import Foundation

enum MyOptional<T> {
    case none
    case some(T)

    init(_ value: T) {
        self = .some(value)
    }

    init() {
        self = .none
    }
}

extension MyOptional {
    /// 运算符重载
    static func ?? (lhs: Self, rhs: T) -> T {
        switch lhs {
        case .none:
            return rhs
        case let .some(T):
            return T
        }
    }
}

var a: MyOptional<Int> = MyOptional()
a = MyOptional(3)
print(a ?? 0)

/* 执行结果
3
Program ended with exit code: 0
*/

这里可以看到,运算符重载后空合并运算符的效果就有了。

三、总结

可选类型在Swift中使用频率非常高,虽然解包需要通过模式匹配稍微影响了性能,但它给应用加了一层保险。合理运用可选类型,可以有效避免因为nil导致的异常问题。