【问题标题】:Swift: How can I make a function with a Subclass return type conform to a protocol, where a Superclass is defined as a return type?Swift:如何使具有子类返回类型的函数符合协议,其中超类被定义为返回类型?
【发布时间】:2016-01-29 22:11:51
【问题描述】:

我有一个协议,其中定义了一个函数,函数的返回类型是SuperclassType

在符合协议的类中,我尝试定义此函数,但返回类型为SubclassType

编译器告诉我,这个类不符合协议,因为显然SubclassType != SuperclassType

protocol SomeProtocol {
  func someFunction(someParameter:SomeType) -> SuperclassType?
}

class SomeClass : SomeProtocol {
  func someFunction(someParameter:SomeType) -> SubclassType? {
    ...
  }
}

class SubclassType : SuperclassType { }

不过,常识告诉我,SubclassType 应该是 SuperclassType 在这件事上的合适替代品。

我做错了什么?

谢谢。

【问题讨论】:

    标签: swift oop protocols


    【解决方案1】:

    在您进一步了解之前,我建议您先阅读一下 covariance vs contravarianceLiskov substitution principle 的背景知识。

    • 方法的返回类型子类化时重写协变的:方法的子类重写可以返回超类的子类型方法的返回类型。

    • 泛型类型参数是不变的:特化既不能缩小也不能扩展类型要求。

    协议和采用它的具体类型之间的关系更像是泛型而不是子类化,因此协议中声明的返回类型也是不变的。 (在第一次阅读时很难说出确切的原因。可能是关于存在与仅约束协议的一些东西?)

    您可以通过指定相关的类型要求来允许协议中的协变:

    protocol SomeProtocol {
        associatedtype ReturnType: SuperclassType
        func someFunction(someParameter: SomeType) -> ReturnType
    }
    
    class SomeClass : SomeProtocol {
        func someFunction(someParameter: SomeType) -> SubclassType { /*...*/ }
    }
    

    现在很明显,采用SomeProtocol的类型中someFunction的返回类型必须是SuperclassType或其子类型。

    【讨论】:

    • 协议中方法的类型参数在协议与采用的超类之间是不变的,但在超类与子类之间是逆变的。
    • 值得注意的是,添加associatedtype 极大地限制了您可以使用协议的方式数量(让我很烦恼) - 它被禁止作为函数参数类型、泛型参数类型、变量类型,您不能从函数中返回一个,也不能将它们组成一个数组。可能大多数其他事情也是如此。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    • 2021-05-24
    • 2020-08-19
    相关资源
    最近更新 更多