除了具有协议扩展的语法之外:
protocol P {}
extension P where Self : UIView {}
...我偶然发现你可以在协议本身上使用相同的where子句:
protocol P where Self : UIView {}
请注意, 与限制通用协议的where子句相同,并且不本身使P成为通用协议。
我的实验似乎表明这里只能使用冒号,结肠后的东西必须是类或协议(可能是通用的)。
我变得很好奇:这是怎么逃避我的注意的?所以我去寻找它何时出现的证据。在Swift 3.0中,前一种语法是合法的,但不是后者。在Swift 3.3中,两者都是合法的。所以后一种语法必须在Swift 3.2之类的东西中悄然引入。我说“悄悄地”,因为我在发行说明中找不到任何相关内容。
第二种语法是什么?它看起来只是一种方便的方法来确保没有其他类型可以采用这个协议吗? Swift标头似乎没有使用它。
答案 0 :(得分:20)
将超类约束放在协议声明上的能力(也就是说,能够定义protocol P where Self : C
C
是类的类型)是一种过早的结果。{{3在实现该功能之前,应该在Swift 4.x中拒绝语法。试图在Swift 4.x SE-0156中使用此功能,所以在Swift 5之前我会避免使用它。
在Swift 5(Xcode 10.2)中,该功能有can cause miscompilation and crashes。来自now been implemented:
协议现在可以将其符合类型限制为那些类型 子类给定的类。支持两种等效形式:
protocol MyView: UIView { /*...*/ } protocol MyView where Self: UIView { /*...*/ }
Swift 4.2接受了第二种形式,但没有完全实现 并且有时可能在编译时或运行时崩溃。 (the release notes) (38077232)
此语法在MyView
上放置一个超类约束,它将符合类型限制为继承自(或正在)UIView
的类型。此外,MyView
的用法在语义上等同于存在类(例如UIView & MyView
),因为您可以访问类的成员和协议对值的要求。
例如,扩展发行说明的例子:
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)