Xcode Swift协议扩展覆盖
我正在试验Swift协议扩展,我发现这种行为相当令人困惑。你能帮我怎么得到我想要的结果吗 请参阅代码最后4行的注释。(如果需要,可以将其复制粘贴到Xcode7游乐场)。谢谢Xcode Swift协议扩展覆盖,xcode,swift,swift2,Xcode,Swift,Swift2,我正在试验Swift协议扩展,我发现这种行为相当令人困惑。你能帮我怎么得到我想要的结果吗 请参阅代码最后4行的注释。(如果需要,可以将其复制粘贴到Xcode7游乐场)。谢谢 protocol Color { } extension Color { var color : String { return "Default color" } } protocol RedColor: Color { } extension RedColor { var color : Stri
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"
简单的回答是,协议扩展不执行类多态性。这是有一定意义的,因为协议可以被结构或枚举采用,而且我们不希望仅仅采用协议就在不必要的地方引入动态调度 因此,在
getColor()
中,color
实例变量(可以更准确地写为self.color
)并不表示您认为它的作用,因为您是以多态方式思考类,而协议不是。所以这是可行的:
let colorB = B().color // is "Red color" - OK
…因为您要求类解析颜色
,但这并不能满足您的要求:
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"!
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
协议的一部分,则可以获得动态行为(即,从而指示编译器合理地期望一致性类实现此方法,并且仅在未找到协议的实现时使用协议的实现):
B
是a
的子类时,为什么会出现一些问题
我认为记住协议扩展中的方法实现是“默认”实现是有帮助的,也就是说,如果一致性类本身没有实现它,那么将使用的实现。您案例中的混淆源于这样一个事实,即B
符合RedColor
,后者具有color
的默认实现,但B
也是a
的子类,后者符合color
,具有不同的color
默认实现
因此,我们可能会质疑斯威夫特对这种情况的处理(就我个人而言,我宁愿看到关于这种固有的模糊情况的警告),但在我看来,问题的根源在于存在两种不同的层次结构(子类的OOP对象层次结构和协议继承的POP协议层次结构)这导致了两个相互竞争的“默认”实现我知道这是一个老生常谈的问题,所以你可能早就转移到其他事情上了,这很好。但是,如果您仍在为重构代码的正确方法而苦苦挣扎,那么请分享一下这个类层次结构和这个协议继承实际上代表了什么,我们可能会提供更具体的建议。这种情况下,抽象的例子会进一步混淆问题。让我们看看真正的类型/协议是什么。(如果您有工作代码,可能是更好的选择。)我在尝试通过协议实现“可选”方法时遇到了这个问题。它可以在结构中、在不继承的类中以及在从实现可重写的非协议默认方法的基继承的类中工作。唯一不起作用的情况是从声明一致性但不提供自己的“非默认”实现的基类继承的类——在这种情况下,协议扩展的默认值是“嵌入”基类的,并且不能被重写或重新定义 简单的例子:
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"!
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
协议的一部分”并不能解决涉及继承的问题,例如。
红莓
继承自蓝莓
,符合协议颜色
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
这里的讨论很好:谢谢你的回答。让我重新定义我的问题:有没有一种方法可以简单地通过向类添加协议来修改某个实例变量?假设我们有class
A
和A.text
是“Hello”
。但是classA:Protocol
会导致A.text
变成“Ciao”
?不,那没有意义。再想一想协议的用途。如果仅仅采用一个协议就比类本身更能说明应该做什么或做什么,那将是可怕的。-但是,请阅读我为您指出的文章,因为它表明,如果将对象引用键入协议,则协议的实现可能比采用者的实现更可取。@VojtaStavik将扩展限制为多个协议extension Lang,其中Self是Lang&意大利语{print(“Ciao”)}