SwiftiOS Developerswift

Swift 4.1 新特性 (1) Conditional Co

2018-03-30  本文已影响223人  面试官小健

随着 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

小结

欢迎关注公众号

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的改进

上一篇下一篇

猜你喜欢

热点阅读