swift - 为什么协议(protocol)中的 get-only 属性要求不能被符合的属性满足?

标签 swift swift-protocols

为什么下面的代码会产生错误?

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
    }
}

The answer in this similar question说得通。但是,在我的示例中,该属性是只获取的。为什么这行不通?这是 Swift 的缺点,还是有什么理由说得通?

最佳答案

没有真正的理由为什么这不可能,只读属性要求可以是协变的,因为返回 ConformsToB来自类型为 ProtocolB 的属性的实例是完全合法的。

Swift 目前不支持它。为此,编译器必须生成 a thunk在协议(protocol)见证表和一致的实现之间,以执行必要的类型转换。例如,ConformsToB实例需要装箱 in an existential container为了输入为 ProtocolB (并且调用者无法做到这一点,因为它可能对被调用的实现一无所知)。

但是,编译器没有理由不能这样做。有多个关于此的错误报告,this one这是特定于只读属性要求的,并且 this general one ,其中 Swift 团队的成员 Slava Pestov 说:

[...] we want protocol witnesses and method overrides in every case where a function conversion is allowed

所以它看起来确实像是 Swift 团队希望在该语言的 future 版本中实现的东西。

然而与此同时,@BallpointBen says , 一种解决方法是使用 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不再用作类型(因为它有 associatedtype 要求)。它还改变了协议(protocol)的内容。最初它说 someProperty可以返回符合 ProtocolB任何 – 现在它说 someProperty 的实现只处理一个符合 ProtocolB特定具体类型.

另一种解决方法是定义一个虚拟属性以满足协议(protocol)要求:

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 添加了一个不必要的属性。

关于swift - 为什么协议(protocol)中的 get-only 属性要求不能被符合的属性满足?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42561685/

相关文章:

swift 2 : How to refer to a type of an element in default implementation of a function in a protocol

swift - 从 swift 协议(protocol)中存储/传递函数类型

ios - 如何检测 iOS 版 SwiftUI 中的 TextField 何时失去焦点?

ios - 使用 CGRect 水平居中并以编程方式提供约束

ios - 如何将一个 UIViewController 作为屏幕的一部分

iOS 核心数据数据保护不起作用

json - 如何通过 Swift 4 的 Decodable 协议(protocol)使用自定义键?

ios - 将类扩展继承子句迁移到协议(protocol)扩展

swift - 为什么我们不能转换为具有关联类型的协议(protocol)类型,而是使用泛型达到相同的效果?

ios - 如何避免委托(delegate)调用的痕迹