Swift:如何使返回子类的函数符合协议,其中父类被定义为返回类型?

7

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

在一个遵循该协议的类中,我尝试定义这个函数,但是返回类型是SubclassType

编译器告诉我,这个类未遵循该协议,因为显然SubclassType != SuperclassType

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

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

class SubclassType : SuperclassType { }

常识告诉我,SubclassType应该是在这个问题中可以替代SuperclassType的合适选择。

我做错了什么?

谢谢。

1个回答

12

在您继续深入之前,我建议您先阅读一些关于协变与逆变以及里氏替换原则的背景知识。

  • 在子类化时被覆盖的方法的返回类型是协变的:子类中覆盖该方法可以返回超类方法返回类型的子类型

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

一个采用协议的具体类型与该协议之间的关系更像是泛型而不是子类化,因此在协议中声明的返回类型也是不变的。(可能是因为第一次阅读时很难准确说明原因。可能涉及到存在性与约束性协议的某些内容?)

但是,您可以通过指定相关类型需求来允许协变性:

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

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

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


方法中的类型参数在协议中是不变的,从采用该协议的超类到子类它们是逆变的。 - Binarian
1
值得注意的是,添加associatedtype会大大限制您可以使用协议的方式(这让我非常恼火)- 它被禁止用作函数参数类型、泛型参数类型、变量类型,您不能从函数中返回它,也不能创建一个数组。可能还有其他大部分情况也是如此。 - Erhannis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接