Swift协议扩展覆盖
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift协议扩展覆盖相关的知识,希望对你有一定的参考价值。
我正在尝试Swift协议扩展,我发现这个令人困惑的行为。你能帮助我如何得到我想要的结果吗?
请参阅代码最后4行的注释。 (如果需要,可以将其粘贴到Xcode7 playground)。谢谢!!
//: 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"
简短的回答是协议扩展不会进行类多态。这是有道理的,因为一个协议可以被struct或enum采用,并且因为我们不希望仅仅采用协议来引入动态调度而不需要它。
因此,在getColor()
中,color
实例变量(可能更准确地写为self.color
)并不意味着你认为它的作用,因为你在思考类多态而协议不是。这样可行:
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中重新定义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"
这里有两个非常不同的问题:协议的动态行为和协议“默认”实现的解决方案。
- 在动态方面,我们可以通过一个简单的例子说明问题:
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
- 现在,在your answer,你质疑为什么当
B
是A
的子类时这有点分崩离析。 我认为有必要记住协议扩展中的方法实现是“默认”实现,即如果符合类本身没有实现它,则使用实现。在你的情况下混淆的根源来自B
符合RedColor
的事实,color
具有B
的默认实现,但A
也是Color
的子类,其符合color
,其具有http://codereview.stackexchange.com的不同默认实现。 所以,我们可能会对Swift对这种情况的处理提出质疑(我个人更愿意看到关于这种固有模糊情况的警告),但在我看来,问题的根源在于有两种不同的层次结构(OOP对象层次结构)子类和协议继承的POP协议层次结构)这导致两个竞争的“默认”实现。
我知道这是一个老问题,所以你可能很久以后就转向了其他事情,这很好。但是,如果您仍在努力寻找重构此代码的正确方法,请分享一下此类层次结构以及此协议继承实际代表的内容,我们可以提供更具体的建议。这是抽象例子进一步混淆问题的案例之一。让我们看看类型/协议到底是什么。 (如果你有工作代码,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
可能是更好的场所。)
我在尝试通过协议实现“可选”方法时遇到了这个问题。它可以在结构中,在不继承的类中工作,也可以在从实现可以被覆盖的非协议默认方法的基础继承的类中工作。唯一不起作用的情况是继承自声明符合性但不提供其自身“非默认”实现的基类的类 - 在这种情况下,协议扩展的默认值是“烘焙”到基类,并且不能被覆盖或重新定义。
简单的例子:
color
注意:建议的解决方案“将Color
定义为原始RedBerry
协议的一部分”并不能解决问题,例如当你有继承时,例如BlueBerry
继承自Color
,符合协议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
。
qazxswpoi
以上是关于Swift协议扩展覆盖的主要内容,如果未能解决你的问题,请参考以下文章