除了这个带有协议(protocol)扩展的语法之外:
protocol P {}
extension P where Self : UIView {}
...我偶然发现您可以在协议(protocol)本身上使用相同的 where 子句:
protocol P where Self : UIView {}
请注意,这不与约束通用协议(protocol)的 where 子句相同,并且不会本身使 P 成为通用协议(protocol)。
我的实验似乎表明,这里只能使用冒号,冒号后面的东西必须是类或协议(protocol)(可能是通用的)。
我开始好奇:这怎么能逃过我的注意?所以我去寻找它何时出现的证据。在 Swift 3.0 中,前一种语法是合法的,但不是后者。在 Swift 3.3 中,两者都是合法的。所以后一种语法一定是在 Swift 3.2 之类的东西中悄悄引入的。我说“悄悄地”是因为我在发行说明中找不到任何相关内容。
第二个语法是做什么用的?看起来,它只是一种确保没有其他类型可以采用此协议(protocol)的便捷方式吗? Swift header 似乎没有使用它。
最佳答案
将父类(super class)约束放在协议(protocol)声明上的能力(即能够定义 protocol P where Self : C
其中 C
是类的类型)是
SE-0156 的过早后果,并且在实现该功能之前,该语法应该在 Swift 4.x 中被拒绝。尝试在 Swift 4.x 中使用此功能 can cause miscompilation and crashes ,所以在 Swift 5 之前我会避免使用它。
在 Swift 5 (Xcode 10.2) 中,该功能具有 now been implemented .来自 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
上放置了一个父类(super class)约束,它将符合类型限制为继承自(或属于)UIView
的类型。此外,MyView
的用法在语义上等同于存在类(例如 UIView & MyView
),因为您可以访问类的成员和协议(protocol)的要求值(value)。
例如,扩展发行说明的示例:
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)
关于带有 "where Self"子句的 Swift 协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50913244/