为什么协议中的 get-only 属性要求不能被符合的属性所满足? [英] Why can't a get-only property requirement in a protocol be satisfied by a property which conforms?

查看:22
本文介绍了为什么协议中的 get-only 属性要求不能被符合的属性所满足?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么下面的代码会报错?

Why does the following code produce an error?

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 的一个缺点,还是有什么理由这样做有意义?

The answer in this similar question makes sense. However, in my example, the property is get-only. Why shouldn't this work? Is it a shortcoming of Swift, or is there some reason this makes sense?

推荐答案

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

There's no real reason why this shouldn't be possible, a read-only property requirement can be covariant, as returning a ConformsToB instance from a property typed as ProtocolB is perfectly legal.

Swift 目前不支持它.为此,编译器必须在协议见证表和符合标准之间生成一个thunk实现以执行必要的类型转换.例如,ConformsToB 实例需要装箱在一个存在的容器中,以便输入为ProtocolB(并且调用者无法做到这一点,因为它可能对被调用的实现一无所知).

Swift just currently doesn't support it. In order to do so, the compiler would have to generate a thunk between the protocol witness table and conforming implementation in order to perform the necessary type-conversion(s). For example, a ConformsToB instance would need to be boxed in an existential container in order to be typed as ProtocolB (and there's no way the caller can do this, as it might not know anything about the implementation being called).

但同样,编译器没有理由不能这样做.有多个错误报告就此打开,this one 特定于只读属性要求,以及这个通用要求,其中 Swift 团队的成员 Slava Pestov,说:

But again, there's no reason why the compiler shouldn't be able to do this. There are multiple bug reports open over this, this one which is specific to read-only property requirements, and this general one, in which Slava Pestov, a member of the Swift team, says:

[...] 在允许函数转换的每种情况下,我们都需要协议见证和方法覆盖

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

所以它看起来肯定是 Swift 团队希望在该语言的未来版本中实现的东西.

So it definitely looks like something the Swift team are looking to implement in a future version of the language.

与此同时,正如 @BallpointBen 说,一种解决方法是使用关联类型:

In the mean time however, as @BallpointBen says, one workaround is to use an 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 要求).它还改变了协议所说的内容.最初它说 someProperty 可以返回符合 ProtocolBanything - 现在它说 someProperty 的实现交易只有一种特定符合ProtocolB的具体类型.

But this is quite unsatisfactory, as it means that ProtocolA is no longer usable as a type (because it has associatedtype requirements). It also changes what the protocol says. Originally it said that someProperty could return anything that conformed to ProtocolB – now it says that an implementation of someProperty deals with just one specific concrete type that conforms to ProtocolB.

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

Another workaround is just to define a dummy property in order to satisfy the protocol requirement:

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

Here we're essentially writing the thunk for the compiler – but it's also not particularly nice as it adds a needless property to the API.

这篇关于为什么协议中的 get-only 属性要求不能被符合的属性所满足?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆