Swift 带有 "where Self" 子句的协议

Swift protocol with "where Self" clause

除了这个带有协议扩展的语法:

protocol P {}
extension P where Self : UIView {}

...我偶然发现您可以在协议本身上使用相同的 where 子句:

protocol P where Self : UIView {}

请注意,这 not 与约束通用协议的 where 子句相同,并且 not 本身是否使 P 成为通用协议.

我的实验似乎表明这里只能使用冒号,冒号后面的东西必须是class或协议(可能是通用的)。

我很好奇:这怎么能逃过我的注意?所以我去寻找它何时出现的证据。在 Swift 3.0 中,前一种语法是合法的,但 不是 后者。在 Swift 3.3 中,两者都是合法的。所以后一种语法一定是在 Swift 3.2 之类的东西中悄悄引入的。我说 "quietly" 是因为我在发行说明中找不到任何相关信息。

第二种语法是做什么用的?看起来,它只是一种确保没有其他类型可以采用此协议的便捷方式吗? Swift headers 似乎没有任何用处。

对协议声明施加超级class约束的能力(即能够定义protocol P where Self : C,其中C是class的类型)是
SE-0156, and the syntax should have been rejected in Swift 4.x until the feature was implemented. Attempting to use this feature in Swift 4.x 的过早后果,所以我会在 Swift 5.

之前避免使用它

在 Swift 5 (Xcode 10.2) 中,特征有 now been implemented. From the release notes:

Protocols can now constrain their conforming types to those that subclass a given class. Two equivalent forms are supported:

protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ } 

Swift 4.2 accepted the second form, but it wasn’t fully implemented and could sometimes crash at compile time or runtime. (SR-5581) (38077232)

此语法在 MyView 上放置了一个 superclass 约束,它将符合类型限制为继承自(或属于)UIView 的类型。此外,MyView 的用法在语义上等同于 class 存在(例如 UIView & MyView),因为您可以访问 class 的成员和协议的要求值。

例如,扩展发行说明的示例:

protocol MyView : UIView {
  var foo: Int { get }
}

class C : MyView {} // error: 'P' requires that 'C' inherit from 'UIView'

class CustomView : UIView, MyView {
  var foo: Int = 0
}

// ...

let myView: MyView = CustomView(frame: .zero)

// We can access both `UIView` members on a `MyView` value
print(myView.backgroundColor as Any)

// ... and `MyView` members as usual.
print(myView.foo)