swift2 Swift协议扩展覆盖

ldxq2e6h  于 2022-11-06  发布在  Swift
关注(0)|答案(5)|浏览(272)

我正在试验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"
z2acfund

z2acfund1#

简短的回答是协议扩展不支持类多态性,这是有一定意义的,因为协议可以被struct或enum采用,而且我们不希望仅仅采用协议就在不必要的地方引入动态调度。
因此,在getColor()中,示例变量color(更准确地说,应该写成self.color)并不意味着你所认为的那样,因为你是从类多态的Angular 来思考的,而协议不是这样。

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

...因为您正在请求一个 * 类 * 解析color,但这并不符合您的预期:

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

...因为getColor方法完全是在协议扩展中定义的。您可以通过在B:

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

现在调用了类的getColor,它对self有一个多态概念。

mccptt67

mccptt672#

这里有两个非常不同的问题:协议的动态行为和协议“默认”实现的解析。
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"!

正如您在your answer中所指出的,如果您将color定义为原始Color协议的一部分,则可以获得动态行为(即,从而指示编译器合理地期望符合协议的类实现此方法,并且仅在未找到任何实现时使用协议的实现):

protocol Color {
    var color: String { get }
}

...

let colorfulThing: Color = BlueBerry()
print("\(colorfulThing.color)")         // now prints "Blue color", as expected

1.现在,在your answer中,您会问为什么当BA的子类时,这福尔斯有点混乱。
我认为记住协议扩展中的方法实现是“默认”实现是很有帮助的,也就是说,如果符合的类本身没有实现它,那么就需要使用它。在您的案例中,混淆的根源在于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可能是更好的选择。)

2w2cym1i

2w2cym1i3#

我设法通过在Color上定义color并切换B的实现列表来使它工作。

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"
hzbexzde

hzbexzde4#

注:当涉及继承时,建议的解决方案“将color定义为原始Color协议的一部分”不能解决问题,例如,RedBerry继承自符合协议ColorBlueBerry

protocol Color {
    var color: String { get }
}

extension Color {
    var color: String { return "Default color" }
}

class BlueBerry: Color {
    //    var color: String { return "Blue color" }
}

class RedBerry: BlueBerry {
    var color: String { return "Red color" }
}

let berry = RedBerry()
print(berry.color)             // Red color

let colorfulThing: Color = RedBerry()
print(colorfulThing.color)     // Actual: Default color, Expected: Red color
ac1kyiln

ac1kyiln5#

我在尝试通过协议实现一个“可选”方法时遇到了这个问题,它 * 可以 * 在结构体中、在不继承的类中工作,也可以在继承自一个基类的类中使用,该基类实现了一个可以覆盖的非协议默认方法。唯一不起作用的情况是继承自一个基类的类声明了一致性,但没有提供自己的“非默认”方法。实现-在这种情况下,协议扩展的默认值是“baked-in”到基类中,并且不能被覆盖或重新定义。
简单的例子:

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

相关问题