为什么具有协议一致性的扩展无法具有特定的访问级别?

时间:2017-08-28 18:50:05

标签: swift protocols swift-extensions access-levels

假设我们有以下示例代码:

protocol MyProtocol {
    func someFunction()
}

public class MyClass {

}

public extension MyClass: MyProtocol {
    func someFunction() {
        print("hello")
    }
}

编译上面的代码会出现以下错误:

  

错误:'公共'修饰符不能与声明协议一致性的扩展名一起使用

如果我将扩展名标记为private,则会发生同样的情况。无论访问级别设置为什么,似乎都无法设置符合协议的扩展的访问级别。即使将协议声明设置为publicprivate,也不会删除错误。

问题

如果Swift符合协议,Swift以这种方式限制扩展访问级别的原因是什么?如果在类级别应用协议一致性,则没有此类限制。

如果我遵守编译器并删除private / public指定,那么someFunction()的访问级别是什么?

extension MyClass: MyProtocol {
    func someFunction() {
        print("hello")
    }
}

我想在这种情况下,它会遵循原来的MyClass实施,并且public但我不确定。

这种行为是否存在,因为扩展中的协议一致性意味着整个类符合协议,因此在扩展中重新指定访问级别是多余的?

3 个答案:

答案 0 :(得分:16)

这是因为除了协议本身的访问级别之外,不可能在任何访问级别上遵循协议。换句话说,如果您使用public协议,则不能private符合该协议。这部分是因为协议一致性是可以在运行时查询的东西(因此在你所在的模块之间不一致,或者在不同的文件/模块中实现两次),部分原因是因为如果一个模块只是很奇怪类型符合一个文件中的协议,并且在其他文件中使用时不符合该协议。

关于someFunction访问级别的问题,它遵循与任何其他功能相同的规则。也就是说,除非类型本身具有较低的访问级别,否则默认为internal。因此,在您的情况下,如果MyClassMyProtocol都是public,那么您可能会收到编译错误,告知您需要将someFunction()标记为public同样。但由于看起来MyProtocol实际上是internal,因此省略任何访问修饰符的工作原理为someFunction(),默认为internal

答案 1 :(得分:2)

私有一致性可能违反 Liskov替代原则

引用苹果开发者论坛的摘要来回答类似的问题:

“我注意到的关于私有一致性(尤其是打算进一步子类化的amonst类)的最大问题是,您经常会遇到冲突的实现。”

例如,您拥有一个私有地遵循协议并实现其所有方法的类。后来出现了一个子类,并希望这样做,但只想实现所需的方法(因为未实现的可选方法可能会提供子类想要的一些默认行为)。但是现在您有两个问题:

1)现在,期望该协议实现的对象可能在同一对象上有2个协议的使用者。这导致两个对象都必须防止意外调用。要么没有,要么由于私有一致性,子类无法调用super来解决意外调用。

2)子类在不修改协议的情况下也无法获得其想要的行为,因为也不能在不影响其行为的情况下删除超类的实现。

来源:Link to Apple Developer forum thread

答案 2 :(得分:1)

  

如果我遵守编译器并删除私人/公共指定,那么someFunction()?的访问级别是什么

无论你说什么。没有什么可以阻止您标记someFunction()的访问级别。但在这种情况下,您无法将其标记为private,因为MyProtocol的访问级别为internal

因此,代码中的默认值为internal。默认情况下,没有任何内容public; public始终是明确的选择加入。