Swift协议扩展覆盖

Voj*_*vik 50 xcode swift swift2

我正在尝试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"
Run Code Online (Sandbox Code Playgroud)

mat*_*att 49

简短的回答是协议扩展不会进行类多态.这是有道理的,因为一个协议可以被struct或enum采用,并且因为我们不希望仅仅采用协议来引入动态调度而不需要它.

因此,在实例中getColor(),color实例变量(可能更准确地写为self.color)并不意味着你认为它的作用,因为你在思考类多态而协议不是.这样可行:

let colorB = B().color // is "Red color" - OK
Run Code Online (Sandbox Code Playgroud)

...因为你要求课程解决color,但这不符合你的期望:

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

...因为该getColor方法完全在协议扩展中定义.您可以通过重新定义getColorB 来解决问题:

class B: A, RedColor {
    func getColor() -> String {
        return self.color
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这个类getColor被称为,它具有多态的概念self.

  • 这里讨论很好:http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future (4认同)

Rob*_*Rob 7

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

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

    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"!
    
    Run Code Online (Sandbox Code Playgroud)

    正如您在回答中指出的那样,如果您将其定义color为原始Color协议的一部分,则可以获得动态行为(即,从而指示编译器合理地期望符合标准的类实现此方法,并且仅在未找到的情况下才使用协议的实现) :

    protocol Color {
        var color: String { get }
    }
    
    ...
    
    let colorfulThing: Color = BlueBerry()
    print("\(colorfulThing.color)")         // now prints "Blue color", as expected
    
    Run Code Online (Sandbox Code Playgroud)
  2. 现在,在您的回答中,您质疑为什么当BA.

    我认为记住协议扩展中的方法实现是“默认”实现会有所帮助,即如果符合的类本身没有实现它,则使用的实现。在您的情况下,混淆的根源来自这样一个事实,即B符合RedColor的默认实现为color,但B也是A符合的子类Color,其具有不同的默认实现color

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

我知道这是一个老问题,所以你可能早就转向其他事情了,这很好。但是,如果您仍在为重构此代码的正确方法而苦苦挣扎,请分享一些有关此类层次结构和此协议继承实际代表的内容的信息,我们可能会提供更具体的建议。这是抽象示例进一步混淆问题的情况之一。让我们看看真正的类型/协议是什么。(如果你有可用的代码,http://codereview.stackexchange.com可能是更好的地方。)


Ian*_*ton 5

我设法得到它的工作通过定义colorColor和切换执行列表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"
Run Code Online (Sandbox Code Playgroud)