繁体   English   中英

Swift,基于扩展协议的类不符合原始协议

[英]Swift, classes based on extended protocol don't conform to original protocol

这些协议让我做噩梦。

我正在尝试实现几个符合它们的协议和类,这样我就可以有默认实现,但是通过扩展协议/类可以使用自定义实现。 到目前为止,这就是我所拥有的:

protocol ProtA {
    var aProperty: String { get set }
    var anotherProperty:String { get set }

    func aFunc (anArgument: String) -> String
}

protocol ProtB: ProtA {
    var aThirdProperty: String { get set }
}

protocol ProtC {
    func doSomething(parameter: Int, with anotherParameter: ProtA)
}

class ClassA: ProtA {
    var aProperty: String = "Hello, I'm a String."
    var anotherProperty: String = "I'm not the same String."

    func aFunc (anArgument: String) -> String {
        return anArgument
    }
}

class ClassB: ProtB {

    var aProperty: String = "Hello, I'm a String."
    var anotherProperty: String = "I'm not the same String."
    var aThirdProperty: String = "I'm yet another String!"

    func aFunc (anArgument: String) -> String {
        return anArgument
    }
}



class ClassC: ProtC {

func doSomething(parameter: Int, with anotherParameter: ProtA) {
    print (anotherParameter.aProperty) // Works fine.

}

}

那么,如果我这样做

class ClassC: ProtC {

    func doSomething(parameter: Int, with anotherParameter: ProtA) {
        print (anotherParameter.aProperty) // Works fine.

    }

}

但是,如果我这样做

class ClassD: ProtC {

    func doSomething(parameter: Int, with anotherParameter: ProtA) {

        print (anotherParameter.aThirdProperty) // Value of type 'ProtA' has no member 'aThirdProperty'

    }

}

而且,如果我这样做

class ClassE: ProtC {

    func doSomething(parameter: Int, with anotherParameter: ProtB) {

        print (anotherParameter.aThirdProperty) // Type 'ClassE' does not conform to protocol 'ProtC'

    }

}

我究竟做错了什么?

问题

从类型继承时,您不能缩小覆盖函数中使用的参数的类型。 这就是您通过将参数从类型ProtA (更通用的类型)更改为ProtB (更具体的类型) ProtB

这是Liskov 替换原则的结果 简单地说,子类必须能够(至少)做超类可以做的所有事情。

ProtC确定所有符合的类型都有一个函数func doSomething(parameter: Int, with anotherParameter: ProtA) ,类型为(Int, ProtA) -> Void)

您在ClassE修改的函数类型为(Int, ProtB) -> Void 但是,此函数不能再替代它所覆盖的函数。

假设有可能做你尝试过的事情。 看看会发生什么:

let instanceConformingToProtA: ProtA = ClassA()

let instanceConformingToProtC: ProtC = ClassE()

// This would have to be possible:
instanceConformingToProtC(parameter: 0, amotherParameter: instanceConformingToProtA)

但是, ClassE()不能instanceConformingToProtA作为其第二个参数的有效参数,因为它是ProtA而不是必需的ProtB

解决方案

此问题的解决方案完全取决于您要实现的目标。 在继续之前,我需要更多信息。

根据经验,当覆盖继承的成员时:

  • 参数类型必须相同,或更通用。
    • 例如,您不能用Car类型的参数覆盖函数,并将参数类型更改为RaceCar 这样做会破坏您的类使用RaceCar的能力,而 LSP 必须能够做到这一点。
    • 例如,您可以使用Car类型的参数覆盖函数,并将参数更改为Vehicle 这样做可以保留您的类使用“车辆”的能力。
  • 返回类型必须相同或更具体。
    • 例如,您不能用返回Vehicle的函数覆盖返回类型为Car的函数。 这样做意味着返回的值比超类保证的“功能更弱”。
    • 例如,您可以使用返回RaceCar的函数覆盖返回类型为Car的函数。 这样做意味着返回的值“更强大”,并且它的作用至少与超类所保证的一样多。

没有什么不对的。 您应该确保声明在语义上是一致的。 您应该创建 ProtD,使用 ProtB 参数声明方法,或者解开获取的 ParamA 参数以将其用作 ProtB。

func doSomething(parameter: Int, with anotherParameter: ProtB) {
     if let a = anotherParameter as? ProtA {
          print (a.aThirdProperty)
     }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM