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

27

除了使用协议扩展的这种语法:

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

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

Translated text:

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

protocol P where Self : UIView {}

请注意,此处所述的“: <Type>”语法不同于限制泛型协议的where从句,它本身并不会使P成为泛型协议。

我的实验似乎表明这里只能使用冒号,冒号后面的内容必须是一个类或协议(可以是泛型的)。

我变得好奇:这是怎么逃脱我注意力的?所以我开始搜寻证据,看看它是在什么时候出现的。在Swift 3.0中,前一种语法合法,但后一种是非法的。在Swift 3.3中,两种语法都是合法的。因此,后一种语法必须是在类似Swift 3.2的版本中悄悄引入的。我说“悄悄”的原因是我在发布说明中找不到任何关于它的内容。

第二个语法是用来干什么的呢?正如它所显示的那样,它只是一种方便的方式,确保没有其他类型可以采用这个协议吗?Swift头文件似乎没有使用它。


6
在协议声明中能够使用 where Self : UIViewSE-0156 的意外结果,该功能尚未完全实现(其实编译器应该在准备好之前拒绝此语法)。目前它还存在许多问题,因此我建议暂时避免使用它 - 参见 https://dev59.com/RFYO5IYBdhLWcg3wKemM#50647762。 - Hamish
4
我认为,@Hamish的评论已经足够好作为答案了。 - Alexander
@Alexander 嗯,它大部分是重复我在链接答案中已经说过的内容,但我想作为这个问题的答案更容易理解...好吧,我会写一个答案 :) - Hamish
可能与Swift论坛中的主题相关:当协议被限制继承自类时会发生什么? - Martin R
1个回答

29
能够在协议声明中放置超类约束(即能够定义protocol P where Self : C,其中C是类的类型)是SE-0156的一个过早的结果,该语法应该在Swift 4.x中被拒绝,直到该功能被实现。在Swift 4.x中尝试使用此功能可能导致错误编译和崩溃,因此我建议在Swift 5之前避免使用它。
在Swift 5(Xcode 10.2)中,该功能已经被实现。来自发行说明

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设置了超类约束,限制符合条件的类型必须从(或是)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)

1
协议 P : UIView {},希望不是这样! - matt
有没有办法实现 protocol P where Self : C & Self: Decodable{}编辑:算了,我可以使用 typealias 来组合 C 和 Decodable,并将 Self 约束为该别名类型... - mfaani
在Swift 5中,您可以编写protocol P where Self : C, Self : Decodable {}protocol P where Self : C & Decodable {}protocol P : C, Decodable {}。然而,在Swift 4.x中,正如我在答案中所讨论的那样,编译器不支持这样的结构。 - Hamish
抱歉,我想询问的是“扩展(extension)”的问题 :) 我之前的评论是不正确的。 - mfaani
@Honey 哦,好的,所以 extension P where Self : C & Decodable {} - Hamish
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接