当前位置: 首页 > 面试题库 >

为什么协议中的仅获取属性要求不能由符合的属性满足?

宣滨海
2023-03-14
问题内容

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

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

这个类似问题的答案很有意义。但是,在我的示例中,该属性为get-only。为什么不行呢?是Swift的缺点,还是有一定的道理呢?


问题答案:

没有真正的理由为什么不可能做到这一点,只读属性要求 可以
是协变的,因为ConformsToBProtocolB完全合法的类型化的属性返回实例。

Swift暂时不支持。为此,编译器将必须在协议见证表和符合的实现之间生成一个thunk,以执行必要的类型转换。例如,一个ConformsToB实例将需要

在一个存在的容器中以便键入为ProtocolB(并且调用者无法执行此操作,因为它可能不知道所调用的实现)。

但是同样,没有理由为什么编译器不应该这样做。对此,存在多个错误报告,该错误报告特定于只读属性要求,而该常规报告中,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不再可以用作一种类型(因为它有associatedtype要求)。它还更改了协议的内容。最初,它说someProperty可以返回
任何 符合条件的 东西ProtocolB –现在,它说的是someProperty交易的实现仅符合一种 特定的
具体类型ProtocolB

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

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



 类似资料:
  • 问题内容: 我正在看自动布局库中的一些代码。其中,UIView采用了一个协议: 一个空虚的成就是什么? 问题答案: 这些是采用协议的类必须为其提供吸气剂的属性。该协议未指定有关setter的任何内容,因此类可以提供计算的属性,而不是存储的属性。 例如,采用的类可以通过添加来满足具有的要求 或通过添加

  • 问题内容: 我想创建一个具有某种类型并且也符合协议的属性,就像我在Objective-C中所做的那样: 我要寻找的是指定可以使用也符合CustomProtocol的UIViewController类型的对象设置属性,以便清楚什么是基类。我知道我可以只使用短类存根来获得相同的结果,即 但这似乎不是最干净的方法。 问题答案: 我想不出一种在Swift中表达这一点的好方法。类型的语法是: 类型→数组类型

  • 我一直在查看Laravel系列的文档和API,但似乎没有找到我想要的: 我想从集合中检索具有模型数据的数组,但只获取指定的属性。 例如,类似于,其中集合实际上包含用户的所有属性,因为它们在其他地方使用,但在这个特定位置,我需要一个包含userdata的数组,并且只包含指定的属性。 在拉雷维尔,似乎没有一个帮手来帮你我怎样才能用最简单的方法做到这一点?

  • 问题内容: 尝试从API获取数据时,在控制台中收到该错误。有人以前有这个问题吗? 错误: 问题答案: 您正在发出格式错误的$ http请求。 您不应在单独调用中设置标头。Call to 实际上会发出请求,但是由于您仅使用标头配置了请求(没有url或方法),因此它会向您抛出该错误(如预期的那样)。 如果要设置标题,则需要通过将自定义配置对象作为第二个参数传递给调用来实现:

  • 问题内容: 在Objective-C中,可以编写如下代码: 但是如何快速编写此代码? 我已经知道如何使一个属性符合许多协议,但是使用继承不能正常工作: 编辑: 我用许多亚型像,或别人,我需要使用一些的属性加在协议定义的一些方法。在最坏的情况下,我可以使用所需的属性创建一个,但是我想知道在Swift中是否可以使用类型和某种协议来声明一个属性/变量。 问题答案: 您可以使用where子句对通用类进行此

  • 我使用JavaFX Scene Builder1.1创建了一个FXML文件。默认情况下创建AnchorPane。为什么我不能修改resizable属性?