Swift 4.1 新特性 (1) Conditional Co
随着 Xcode 9.3 的正式版发布,Swift 4.1 和 iOS 11.3 也一同正式亮相,Swift 4.1 加了什么呢?语言方面主要是围绕泛型做了加强。首先我们来了解一下 Conditional Conformance。
我们知道 Array 是个泛型 struct ,它有个类型参数是 Element 。现在我们想让 Array 实现 Equatable 协议,当然有个条件,需要实际的 Element 类型本身实现 Equatable 。这是个很自然的条件,因为如果 Element 不支持相等比较的话,我们也没有办法写出 Array 的相等比较扩展。
上面这一段话其实就在描述 Conditional Conformance(在一定条件下的实现) ,于是我们很自然地会这么写:
extension Array: Equatable where Element: Equatable {
static func == (lhs: Array<Element>, rhs: Array<Element>) -> Bool {
return true
}
}
很遗憾,这段代码在 Swift 4.0 当中是编译不过的,第一行报错
Extension of type 'Array' with constraints cannot have an inheritance clause
这里:Equatable
冒犯了 Swift 4.0 的编译器,有 where 子句的扩展就不能有继承子句。
在 Swift 4.1 中,这个特性得以被支持。大家可以练习一下实现这个方法代替 return true
。而事实上,新的标准库已经加入了这个扩展。另外,这里有个旧知识的复习, Equatable 还有个 != 方法为什么不需要实现呢?答案是默认实现。
我们来看一下这个扩展的用途:多维数组的比较,这里a1和a2都是 Array< Array <Int> > ,我们看到由于 Int 是 Equatable ,所以 Array< Int > 也是 Equatable ,因此 Array< Array < Int > > 是Equatable,可以直接比较。
let a1 = [[123], [456,789]]
let a2 = [[123], [456,789]]
let a3: [[Int]] = []
print(a1 == a2) // true
print(a1 == a3) // false
关于 Conditional Conformance 还有一个非常重要的特性,就是它对于运行时检查 conformance 的支持。来看下面的代码:
protocol P {
func doSomething()
}
struct S: P {
func doSomething() { print("S") }
}
extension Array: P where Element: P {
func doSomething() {
for value in self {
value.doSomething()
}
}
}
// compile-time
func doSomethingStatically<E: P>(_ value:Array<E>) {
value.doSomething()
}
// runtime
func doSomethingIfP(_ value: Any) {
if let p = value as? P {
p.doSomething()
}
}
doSomethingIfP([S(), S(), S()])
我们看到了两个版本,前者是编译器确定了这个扩展的有效性;后者是 runtime 的时候做检查,它体现了 Conditional Conformance 对动态检查的支持。
如何来直观感受运行时检查 Conditional Conformance 这个特性的作用呢?我们可以想象是自己是被传入的参数:我是个普通的 Array,只不过我的元素类型实现了 P。结果发现我实现了个新的 protocol P,并且拥有了新方法 doSomething
。哪怕我是被作为 Any 类型传入的,动态也能判断上述事实。我只是个 Array ,元素类型实现了 P 而已。 Conditional Conformance 的扩展使这一切成为可能。
最后再回顾一个知识点,为什么我们最后需要新写个 protocol P 来举例,不直接用前面的 Equatable 呢?
用另一个问题可以回答:在Swift中,可不可以写 as? Equatable
,或者 var e : Equatable = 10
呢?其实是不能的,因为Equatable这样的protocol只能作为泛型的类型约束,而不能作为可以直接hold值的类型,原因是它有 associated type 或者Self
;也没有Equatable<Int> 的写法,Equatable 不是泛型类型,只是泛型约束。
核心内容就是以上这些,想了解更多,可以看下这个 proposal Conditional Conformances
小结
- 介绍了 Conditional Conformance 的语法和语义
- 以 Array 为例介绍了 Conditional Conformance 用途以及标准库的引入
- Conditional Conformance 支持动态判断
Swift 4.1 新特性系列文章
Swift 4.1 新特性 (1) Conditional Conformance
Swift 4.1 新特性 (2) Sequence.compactMap
Swift 4.1 新特性 (3) 合成 Equatable 和 Hashable
Swift 4.1 新特性 (4) Codable的改进