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

37

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

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,但我不确定。

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

3个回答

34
这是因为除了协议本身的访问级别,无法使用任何其他访问级别符合协议。换句话说,如果您有一个公共协议,您无法对其进行私有符合。这部分是因为协议符合是可以在运行时查询的(因此不能在不同模块中间有所区别或在不同文件/模块中执行两次),部分原因是如果一种类型在一个文件中符合一个协议,在其他文件中使用该类型时不符合该协议将会很奇怪。
至于你关于someFunction访问级别的问题,它遵循与任何其他函数相同的规则。也就是说,它默认为内部访问级别,除非类型本身具有较低的访问级别。因此,在您的情况下,如果MyClass和MyProtocol都是public,则可以期待编译器错误提示您需要将someFunction()标记为public。但由于看起来MyProtocol实际上是内部的,因此省略任何访问修饰符将作为someFunction()默认为internal。

5

私有符合性可能会违反里氏替换原则

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

“我注意到关于私有符合性最大的问题,尤其是在那些打算进一步派生子类的类中,是你经常会遇到冲突的实现。”

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

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

2)没有办法使子类获得它想要的行为,而不修改协议,因为超类的实现不能被删除,否则会影响其行为。

来源:链接到苹果开发者论坛线程


1
如果我听从编译器并删除private/public标记,那么someFunction()的访问级别是什么?
你说了算。你可以标记someFunction()的访问级别。但在这种情况下,你不能将其标记为private,因为MyProtocol的访问级别是internal
因此,在你的代码中,默认值为internal。没有任何东西默认为publicpublic始终是明确的选择。

3
公共扩展中的函数默认为公共 :) - J. Doe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接