30

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

protocol MyProtocol {
    func someFunction()
}

public class MyClass {

}

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

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

错误:“public”修饰符不能与声明协议一致性的扩展一起使用

如果我将扩展名标记为private. 似乎您无法设置符合协议的扩展的访问级别,无论访问级别设置为什么。即使将协议声明设置为publicprivate不会消除错误。

问题

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

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

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

我想在这种情况下它会遵循原始MyClass实现,public但我不确定。

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

4

3 回答 3

28

这是因为除了协议本身的访问级别之外,不可能在任何访问级别上符合协议。换句话说,如果你有一个public协议,你就不能private遵守它。这部分是因为协议一致性是可以在运行时查询的(因此在你所在的模块之间不能有区别,或者在不同的文件/模块中实现两次),部分是因为如果一个type 符合一个文件中的协议,但在其他文件中使用时不符合该协议。

至于您对 的访问级别的问题someFunction,它遵循与任何其他功能相同的规则。也就是说,它默认为internal,除非类型本身具有较低的访问级别。因此,在您的情况下, ifMyClassMyProtocolare both public,您可能会收到一个编译器错误,告诉您也someFunction()需要标记public。但由于实际上看起来像MyProtocolis internal,因此省略任何访问修饰符someFunction()默认为internal.

于 2017-08-28T18:58:43.780 回答
4

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

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

“关于私有一致性,我注意到的最重要的事情是,尤其是在那些打算进一步子类化的类中,你经常会遇到相互冲突的实现。”

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

1) 期望此协议实现的对象现在可能在同一对象上有 2 个协议消费者。这导致两个对象都必须防范意外调用。或者没有,由于私有一致性,子类不能调用 super 来解决意外调用。

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

资料来源:Apple 开发者论坛主题的链接

于 2018-07-09T18:00:29.907 回答
1

如果我服从编译器并删除私有/公共指定,那么访问级别是多少someFunction()?

不管你说什么。没有什么能阻止您标记someFunction(). 但在这种情况下,您不能将其标记为private,因为 MyProtocol 的访问级别是internal

因此,默认值internal在您的代码中。没有什么是public默认的;public始终是一个明确的选择加入指定。

于 2017-08-28T18:58:36.663 回答