简体   繁体   English

返回泛型时的 Swift 协议一致性

[英]Swift protocol conformance when returning a generic

Here's an example:这是一个例子:

protocol Feed {
    func items<T>() -> [T]? where T: FeedItem
}

protocol FeedItem {}

class FeedModel: Feed, Decodable {
    func items<T>() -> [T]? where T : FeedItem {
        return [FeedItemModel]() // Error: Cannot convert return expression of type '[FeedItemModel]' to return type '[T]?'
    }
}

class FeedItemModel: FeedItem, Decodable {}

Why does it:为什么这样做:

A) try to convert to T when T is a generic, not a type? A)当T是泛型而不是类型时尝试转换为T B) does not recognize FeedItemModel as conforming to FeedItem ? B) 不承认FeedItemModel符合FeedItem

func items<T>() -> [T]? where T : FeedItem

This says that the caller can define T to be whatever they want, as long as T conforms to FeedItemModel, and this function will return an optional array of those.这表示调用者可以将T定义为他们想要的任何内容,只要T符合 FeedItemModel,并且此 function 将返回这些的可选数组。

FeedItemModel is something that conforms to FeedItem, but it is not promised to be the type T that the caller requested. FeedItemModel 是符合 FeedItem 的东西,但不承诺是调用者请求的类型T

As an example, consider:例如,考虑:

class OtherModel: FeedItem {}

According to your function signature, I can do this:根据您的 function 签名,我可以这样做:

let ms: [OtherModel]? = FeedModel().items()

But your function won't then return [OtherModel]?但是您的 function 不会返回[OtherModel]? to me.大部头书。 I suspect you don't actually mean this to be generic.我怀疑您实际上并不是说这是通用的。 I expect you mean:我希望你的意思是:

func items() -> [FeedItemModel]?

or possibly或者可能

func items() -> [FeedItem]?

(Though I would think very hard before doing the latter one and make sure that the protocol existential is really doing useful work here.) (虽然在做后一个之前我会非常努力地思考,并确保协议存在确实在这里做了有用的工作。)

A)一个)

T is a type, a homogenous concrete type specified at runtime. T一种类型,一种在运行时指定的同质具体类型。
Imaging T is class Foo: FeedItem it's obvious that FeedItemModel cannot be converted to Foo成像Tclass Foo: FeedItem很明显FeedItemModel不能转换为Foo

B)二)

FeedItemModel is recognized as conforming to FeedItem but this is irrelevant. FeedItemModel被识别为符合FeedItem但这无关紧要。


It's often a mix-up of generics and protocols.它通常是 generics 和协议的混淆。 Generic types are not covariant.泛型类型不是协变的。 If you need covariant types use an associated type.如果您需要协变类型,请使用关联类型。

Either you can ignore generics because because it only applies to that one function and it isn't needed since directly saying that the return type is [FeedItem]?你可以忽略 generics 因为它只适用于那个 function 并且不需要它,因为直接说返回类型是[FeedItem]? yields the same result产生相同的结果

protocol Feed {
    func items() -> [FeedItem]?
}

class FeedModel: Feed, Decodable {
    func items() -> [FeedItem]?  {
        return [OtherModel]()
    }
}

If you on the other hand want a generic protocol then you should use a associated type另一方面,如果您想要一个通用协议,那么您应该使用关联类型

protocol Feed2 {
    associatedtype T: FeedItem

    func items() -> [T]?
}

class FeedModel2: Feed2, Decodable {
    typealias T = FeedItemModel
    func items() -> [T]?  {
        return [FeedItemModel]()
    }
}

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

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