为什么在一个协议中只能得到一个只能得到的属性需求才能被一个符合的属性满足?
为什么下面的代码会产生一个错误?
protocol ProtocolA { var someProperty: ProtocolB { get } } protocol ProtocolB {} class ConformsToB: ProtocolB {} class SomeClass: ProtocolA { // Type 'SomeClass' does not conform to protocol 'ProtocolA' var someProperty: ConformsToB init(someProperty: ConformsToB) { self.someProperty = someProperty } }
这个类似的问题的答案是有道理的。 但是,在我的示例中,该属性是只能获取的。 为什么不能这样工作? 这是Swift的一个缺点,还是有一些原因,这是有道理的?
没有真正的原因,为什么这是不可能的,只读属性需求可以是协变的,因为从types为ProtocolB
的属性返回ConformsToB
实例是完全合法的。
目前Swift不支持它。 为了做到这一点,编译器将不得不在协议见证表和符合实现之间生成一个thunk ,以便执行必要的types转换。 例如, ConformsToB
实例需要在存储容器中装箱 ,以便作为ProtocolB
input(而且调用者无法做到这一点,因为它可能不知道被调用实现的任何内容)。
但是,再次,没有理由为什么编译器不应该能够做到这一点。 这里有多个bug报告, 这是一个特定于只读属性需求的bug报告,而这个通用报告中,Swift团队的成员Slava Pestov说:
我们希望在每个允许进行函数转换的情况下,协议证人和方法覆盖
所以它看起来像Swift团队正在寻求在未来版本的语言中实现的东西。
但是,同时@BallpointBen说 ,一个解决方法是使用一个associatedtype
:
protocol ProtocolA { // allow the conforming type to satisfy this with a concrete type // that conforms to ProtocolB. associatedtype SomeProperty : ProtocolB var someProperty: SomeProperty { get } } protocol ProtocolB {} class ConformsToB: ProtocolB {} class SomeClass: ProtocolA { // implicitly satisfy the associatedtype with ConformsToB. var someProperty: ConformsToB init(someProperty: ConformsToB) { self.someProperty = someProperty } }
但是这是不太令人满意的,因为这意味着ProtocolA
不再可用作types(因为它具有associatedtype
的types要求)。 它也改变了协议所说的内容。 最初它说someProperty
可以返回任何符合ProtocolB
东西 – 现在它说一个someProperty
的实现只处理一个符合ProtocolB
特定具体types。
另一个解决方法就是定义一个虚拟属性以满足协议要求:
protocol ProtocolA { var someProperty: ProtocolB { get } } protocol ProtocolB {} class ConformsToB: ProtocolB {} class SomeClass: ProtocolA { // dummy property to satisfy protocol conformance. var someProperty: ProtocolB { return actualSomeProperty } // the *actual* implementation of someProperty. var actualSomeProperty: ConformsToB init(someProperty: ConformsToB) { self.actualSomeProperty = someProperty } }
在这里,我们基本上是为编译器编写了一个thunk ,但是它也不是特别好,因为它增加了一个不必要的属性给API。