Swift协议扩展覆盖

我正在尝试使用Swift协议扩展,我发现这很令人困惑的行为。 你能帮我怎么得到我想要的结果吗?

请参阅代码最后4行的注释。 (如果你愿意,你可以复制粘贴到XCode7游乐场)。 谢谢!!

//: Playground - noun: a place where people can play import UIKit 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" 

简单的答案是协议扩展不会做类多态。 这是有一定意义的,因为一个协议可以被一个结构或枚举所采用,并且因为我们不希望仅仅采用一个协议来引入dynamic分配,而不需要这个协议。

因此,在getColor()color实例variables(可能会更准确地写成self.color )并不意味着您认为它的作用,因为您正在考虑类多态,而协议不是。 所以这个工作:

 let colorB = B().color // is "Red color" - OK 

…因为你要求一个class级去解决color ,但是这不符合你的期望:

 let b = B().getColor() // is "Default color" BUT I want it to be "Red color" 

…因为getColor方法完全是在协议扩展中定义的。 你可以通过在B中重新定义getColor来解决这个问题:

 class B: A, RedColor { func getColor() -> String { return self.color } } 

现在该类的getColor被调用,并且它具有什么是self的多态概念。

我设法通过在Color上定义Color并切换B的实现列表来实现它的工作。如果B必须是A那么它不是很好。

 protocol Color { var color : String { get } } protocol RedColor: Color { } extension Color { var color : String { get {return "Default color"} } } extension RedColor { var color : String { get {return "Red color"} } } protocol PrintColor { func getColor() -> String } extension PrintColor where Self: Color { func getColor() -> String { return color } } class A : Color, PrintColor { } class B : RedColor, PrintColor { } let a = A().getColor() // "Default color" let b = B().getColor() // "Red color" 

这里有两个非常不同的问题:协议的dynamic行为和协议“默认”实现的parsing。

  1. 在dynamic方面,我们可以用一个简单的例子来说明问题:

     protocol Color { } extension Color { var color: String { return "Default color" } } class BlueBerry: Color { var color: String { return "Blue color" } } let berry = BlueBerry() print("\(berry.color)") // prints "Blue color", as expected let colorfulThing: Color = BlueBerry() print("\(colorfulThing.color)") // prints "Default color"! 

    正如你在答案中指出的那样,如果将color定义为原始Color协议的一部分,则可以获得dynamic行为(即从而指示编译器合理地期望符合类实现此方法,并且只使用协议的实现find):

     protocol Color { var color: String { get } } ... let colorfulThing: Color = BlueBerry() print("\(colorfulThing.color)") // now prints "Blue color", as expected 
  2. 现在,在你的回答中 ,你质疑为什么当BA一个子类时,这个分裂了一点。

    我认为这有助于记住协议扩展中的方法实现是“默认”实现,也就是说,如果合规类本身没有实现它,将使用实现。 在你的情况下,混淆的来源是这样的事实, B符合RedColor它有一个默认的color实现,但B也是一个符合Color ,具有不同的默认实现的colorA的子类。

    所以,我们可能会质疑Swift处理这种情况(个人而言,我宁愿看到这个本质上模棱两可的情况的警告),但在我看来,问题的根源是有两个不同的层次结构(OOP对象层次结构子类和协议inheritance的POP协议层次结构),这导致两个竞争的“默认”实现。

我知道这是一个古老的问题,所以你可能早已转向其他事情,这很好。 但是如果你仍然在为重构这个代码的正确方法而苦苦挣扎,那就分享一下这个类层次结构以及这个协议inheritance的实际代表,我们可能会提供更具体的build议。 这是抽象例子进一步混淆了这个问题的例子之一。 让我们来看看types/协议真的是什么。 (如果你有工作代码, http://codereview.stackexchange.com可能是更好的地方。);

我遇到这个问题,同时试图通过协议实施“可选”的方法。 可以在结构中,在不inheritance的类中工作,也可以在inheritance自实现可以被覆盖的非协议默认方法的基类的类中工作。 唯一不起作用的是一个从声明符合性但不提供自己的“非默认”实现的基类inheritance而来的类 – 在这种情况下,协议扩展的默认是“烘焙到”基类,并且不能被覆盖或重新定义。

简单的例子:

 typealias MyFunction = () -> () protocol OptionalMethod { func optionalMethod() -> MyFunction? func executeOptionalMethod() } extension OptionalMethod { func optionalMethod() -> MyFunction? { return nil } func executeOptionalMethod() { if let myFunc = self.optionalMethod() { myFunc() } else { print("Type \(self) has not implemented `optionalMethod`") } } } class A: OptionalMethod { } class B: A { func optionalMethod() -> MyFunction? { return { print("Hello optional method") } } } struct C: OptionalMethod { func optionalMethod() -> MyFunction? { return { print("Hello optionalMethod") } } } class D: OptionalMethod { func optionalMethod() -> MyFunction? { return { print("Hello optionalMethod") } } } class E: D { override func optionalMethod() -> MyFunction? { return { print("Hello DIFFERENT optionalMethod") } } } /* Attempt to get B to declare its own conformance gives: // error: redundant conformance of 'B2' to protocol 'OptionalMethod' class B2: A, OptionalMethod { func optionalMethod() -> MyFunction? { return { print("Hello optional method") } } } */ class A2: OptionalMethod { func optionalMethod() -> MyFunction? { return nil } } class B2: A2 { override func optionalMethod() -> MyFunction? { return { print("Hello optionalMethod") } } } let a = A() // Class A doesn't implement & therefore defaults to protocol extension implementation a.executeOptionalMethod() // Type __lldb_expr_201.A has not implemented `optionalMethod` let b = B() // Class B implements its own, but "inherits" implementation from superclass A b.executeOptionalMethod() // Type __lldb_expr_205.B has not implemented `optionalMethod` let c = C() // Struct C implements its own, and works c.executeOptionalMethod() // Hello optionalMethod let d = D() // Class D implements its own, inherits from nothing, and works d.executeOptionalMethod() // Hello optionalMethod let e = E() // Class E inherits from D, but overrides, and works e.executeOptionalMethod() // Hello DIFFERENT optionalMethod let a2 = A2() // Class A2 implements the method, but returns nil, (equivalent to A) a2.executeOptionalMethod() // Type __lldb_expr_334.A2 has not implemented `optionalMethod` let b2 = B2() // Class B2 overrides A2's "nil" implementation, and so works b2.executeOptionalMethod() // Hello optionalMethod