我正在试验Swift协议扩展,我发现这种行为相当令人困惑。你能帮助我如何得到我想要的结果吗?
请看代码最后4行的注解。(如果你愿意的话,可以复制粘贴到Xcode 7操场上)。谢谢!!
protocol Color { }
extension Color { var color : String { return "Default color" } }
protocol RedColor: Color { }
extension RedColor { var color : String { return "Red color" } }
protocol PrintColor {
func getColor() -> String
}
extension PrintColor where Self: Color {
func getColor() -> String {
return color
}
}
class A: Color, PrintColor { }
class B: A, RedColor { }
let colorA = A().color // is "Default color" - OK
let colorB = B().color // is "Red color" - OK
let a = A().getColor() // is "Default color" - OK
let b = B().getColor() // is "Default color" BUT I want it to be "Red color"
5条答案
按热度按时间z2acfund1#
简短的回答是协议扩展不支持类多态性,这是有一定意义的,因为协议可以被struct或enum采用,而且我们不希望仅仅采用协议就在不必要的地方引入动态调度。
因此,在
getColor()
中,示例变量color
(更准确地说,应该写成self.color
)并不意味着你所认为的那样,因为你是从类多态的Angular 来思考的,而协议不是这样。...因为您正在请求一个 * 类 * 解析
color
,但这并不符合您的预期:...因为
getColor
方法完全是在协议扩展中定义的。您可以通过在B:现在调用了类的
getColor
,它对self
有一个多态概念。mccptt672#
这里有两个非常不同的问题:协议的动态行为和协议“默认”实现的解析。
1.在动态方面,我们可以用一个简单的例子来说明这个问题:
正如您在your answer中所指出的,如果您将
color
定义为原始Color
协议的一部分,则可以获得动态行为(即,从而指示编译器合理地期望符合协议的类实现此方法,并且仅在未找到任何实现时使用协议的实现):1.现在,在your answer中,您会问为什么当
B
是A
的子类时,这福尔斯有点混乱。我认为记住协议扩展中的方法实现是“默认”实现是很有帮助的,也就是说,如果符合的类本身没有实现它,那么就需要使用它。在您的案例中,混淆的根源在于
B
符合RedColor
,而RedColor
有一个color
的默认实现,但是x1M7 N1 X也是x1M8 N1 X的子类,它符合x1M9 N1 X,而x1M9 N1 X具有不同的x1M10 N1 X的默认实现。因此,我们可能会对Swift对这种情况的处理提出质疑(就我个人而言,我更希望看到一个关于这种固有的模棱两可的情况的警告),但在我看来,问题的根源在于存在两个不同的层次结构(子类的OOP对象层次结构和协议继承的POP协议层次结构),这导致了两个竞争的“默认”实现。
我知道这是一个老问题,所以您可能早就转移到其他事情上了,这没关系,但是如果您还在为重构代码的正确方法而挣扎,分享一点关于这个类层次结构和这个协议继承实际上代表什么,我们也许能够提供更具体的建议。这是那些抽象的例子只会进一步混淆问题的情况之一。让'让我们看看类型/协议到底是什么。(如果您有工作代码,http://codereview.stackexchange.com可能是更好的选择。)
2w2cym1i3#
我设法通过在
Color
上定义color
并切换B的实现列表来使它工作。hzbexzde4#
注:当涉及继承时,建议的解决方案“将
color
定义为原始Color
协议的一部分”不能解决问题,例如,RedBerry
继承自符合协议Color
的BlueBerry
。ac1kyiln5#
我在尝试通过协议实现一个“可选”方法时遇到了这个问题,它 * 可以 * 在结构体中、在不继承的类中工作,也可以在继承自一个基类的类中使用,该基类实现了一个可以覆盖的非协议默认方法。唯一不起作用的情况是继承自一个基类的类声明了一致性,但没有提供自己的“非默认”方法。实现-在这种情况下,协议扩展的默认值是“baked-in”到基类中,并且不能被覆盖或重新定义。
简单的例子: