斯威夫特:如何让具有子类返回类型的函数符合协议,在协议中将超类定义为返回类型?

斯威夫特:如何让具有子类返回类型的函数符合协议,在协议中将超类定义为返回类型?

问题描述:

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

I have a protocol, where a function is defined, the return type of a function is a SuperclassType.

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

In a class which conforms to the protocol I'm trying to define this function, but with a SubclassType return type.

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

Compiler tells me, that this class does not conform to the protocol, because obviously SubclassType != SuperclassType

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

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

class SubclassType : SuperclassType { }

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

Common sense tells me, though, that SubclassType should be a suitable substitute for a SuperclassType in this matter.

我在做什么错了?

谢谢.

在进一步介绍之前,我建议您先阅读李斯科夫替代原则.

Before you go much further, I'd recommend some background reading on covariance vs contravariance and the Liskov substitution principle.

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

  • Return types for methods overridden when subclassing are covariant: the subclass override of a method can return a subtype of the superclass method's return type.

通用类型参数是不变:专业化既不能缩小也不能扩展类型要求.

Generic type parameters are invariant: a specialization can neither narrow nor expand the type requirements.

协议和采用该协议的具体类型之间的关系更像泛型而不是子类,因此协议中声明的返回类型也是不变的. (很难说清楚为什么要初读.可能是关于存在性协议和仅约束协议的某些内容?)

The relationship between a protocol and a concrete type that adopts it is more like generics than like subclassing, so return types declared in protocols are invariant, too. (It's hard to say exactly why on first read. Possibly something about existential vs constraint-only protocols?)

您可以通过指定关联的类型要求来允许协议中的协方差,

You can allow covariance in a protocol by specifying associated type requirements, though:

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

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

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

Now, it's clear that the return type of someFunction in a type adopting SomeProtocol must be either SuperclassType or a subtype thereof.