Swift 标准库阅读笔记 - Optional

Posted by Phillip Song on 2019-06-06

Optional 是 Swift 重要的语言特性之一,通过引入 Optional, 可以很好的判断变量是否存在 nil 值的情况,可以很好的防止出现因为未处理 nil 而带来的程序崩溃问题。

下面让我们通过源码来了解一下 Optional 具体的实现逻辑。

Optional 具体的实现是一个包含 .none.some 两个 case 的 enum。

1
2
3
4
5
6
7
8
9
10
11
12
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)

public init(_ some: Wrapped) {
self = .some(some)
}

public init(nilLiteral: ()) {
self = .none
}
}

init

由于 Optional 是多类型的,因此我们通过 <Wrapped> 来声明范型。

初始化方法init(_ some:) 可以用来初始化一个非 nil 的实例。 而遵守 ExpressibleByNilLiteral 协议则定义了一个初始化方法init(nilLiteral:), 可以使用 nil 初始化一个实例。

map

1
2
3
4
5
6
7
8
public func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? {
switch self {
case .some(let y):
return .some(try transform(y))
case .none:
return .none
}
}

Optional 类型执行 map 方法时,如果值为 .none 时,直接返回 nil。如果为 .some(Wrapped) 时,返回 .some(transform(Wrapped)), 即仍会返回 Optional 类型,仍需进行解包。

可用如下代码验证:

1
2
3
4
5
6
7
8
9
let possibleNumber: Int? = Int("42")
let possibleSquare = possibleNumber.map { $0 * $0 }
print(possibleSquare)
// "Optional(1764)"

let noNumber: Int? = nil
let noSquare = noNumber.map { $0 * $0 }
print(noSquare)
// "nil"

flatMap

1
2
3
4
5
6
7
8
9
public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U? {
switch self {
case .some(let y):
return try transform(y)
case .none:
return .none
}
}
}

而在使用 flatMap 时, 如果值为 nil 时,直接返回 nil, 如果不为 nil,会进行解包并执行闭包。需要注意的是,transform 时是解包值,但 return 返回的还是 Optional

1
2
3
4
5
6
7
let possibleNumber: Int? = Int("42")
let nonOverflowingSquare = possibleNumber.flatMap { x -> Int? in
let (result, overflowed) = x.multipliedReportingOverflow(by: x)
return overflowed ? nil : result
}
print(nonOverflowingSquare)
// Prints "Optional(1764)"

UnsafelyUnwrapped

1
2
3
4
5
6
7
8
9
public var unsafelyUnwrapped: Wrapped {
@inline(__always)
get {
if let x = self {
return x
}
_debugPreconditionFailure("unsafelyUnwrapped of nil optional")
}
}

unsafelyUnwrapped 和 强制解包符 ! 的功能是相似的,如果为 .none 时会报错。

1
2
3
4
5
6
7
let possibleNumber: Int? = Int("42")
print(possibleNumber.unsafelyUnwrapped)
// 42

let noNumber: Int? = nil
print(noNumber.unsafelyUnwrapped)
// Fatal error: unsafelyUnwrapped of nil optional

Nil Coalescing (??)

1
2
3
4
5
6
7
8
9
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}

上面就是我们在解包时常用的 ?? 操作符,它强制要求可能为 nil 的变量放在左边, 默认值写在右边。当 Optional.none 的时候,则返回 defaultValue 的值。

== & !=

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static func ~=(lhs: _OptionalNilComparisonType, rhs: Wrapped?) -> Bool {
switch rhs {
case .some:
return false
case .none:
return true
}
}

public static func ==(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool {
switch lhs {
case .some:
return false
case .none:
return true
}
}

public static func !=(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool {
switch lhs {
case .some:
return true
case .none:
return false
}
}

其中重载的一些操作符,用来比较 Optional 类型与 nil 进行, 即我们进行判空时调用的方法。

_ObjectiveCBridgeable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
associatedtype _ObjectiveCType : AnyObject

/// Convert `self` to Objective-C.
func _bridgeToObjectiveC() -> _ObjectiveCType

static func _forceBridgeFromObjectiveC(
_ source: _ObjectiveCType,
result: inout Self?
)

@discardableResult
static func _conditionallyBridgeFromObjectiveC(
_ source: _ObjectiveCType,
result: inout Self?
) -> Bool

static func _unconditionallyBridgeFromObjectiveC(_ source: _ObjectiveCType?)
-> Self

实现的目的主要用来 Swift 跟 Objective C 中类型进行桥接。Swift 的 ArrayDictionary 等遵守这个协议的类型可以转换成OC中对应的 NSArrayNSDictionary 类型。

上面就是对 Optional 类型的源码分析,可以看出实现十分巧妙,通过 enum 类型的特性便实现了 Optional 所需要的功能。