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

Swift protocol conformance when returning a generic

这是一个例子:

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 {}

为什么会这样:

A) 当 T 是泛型而非类型时尝试转换为 T? B) 不承认 FeedItemModel 符合 FeedItem?

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

这表示调用者可以将 T 定义为任何他们想要的,只要 T 符合 FeedItemModel,并且此函数将 return 一个可选的数组。

FeedItemModel 是符合 FeedItem 的东西,但未承诺是调用者请求的类型T

例如,考虑:

class OtherModel: FeedItem {}

根据你的函数签名,我可以这样做:

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

但是你的函数不会 return [OtherModel]? 给我。我怀疑您实际上并不是说这是通用的。我想你的意思是:

func items() -> [FeedItemModel]?

或者可能

func items() -> [FeedItem]?

(虽然在做后一个之前我会非常认真地思考并确保协议存在在这里真的做了有用的工作。)

A)

T 一种类型,一种在运行时指定的同构具体类型。
成像 Tclass Foo : FeedItem 显然 FeedItemModel 不能转换为 Foo

B)

FeedItemModel 被认为符合 FeedItem 但这无关紧要。


它通常是 mix-up 泛型和协议。泛型类型不是协变的。如果您需要协变类型,请使用关联类型。

要么你可以忽略泛型,因为它只适用于那个函数并且不需要它,因为直接说 return 类型是 [FeedItem]? 会产生相同的结果

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

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

另一方面,如果您想要通用协议,那么您应该使用关联类型

protocol Feed2 {
    associatedtype T: FeedItem

    func items() -> [T]?
}

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