我有一个名为APIRequest
的协议,其关联类型为ResponseType
和一个解码函数。这个例子并不完整,但是我相信这些是问题的唯一相关部分。
还有一个名为ArrayResponse
的结构,用于表示网络响应何时以items
个不同对象的数组形式返回(取决于特定的APIRequest
的ResponseType
和totalItems
。
protocol APIRequest { associatedtype ResponseType: Codable /// Decodes the request result into the ResponseType func decode(_: Result<Data, APIError>) throws -> ResponseType } struct ArrayResponse<T>: Codable where T: Codable { let items: [T] let totalItems: Int }
这是一个遵循
APIRequest
协议并将其ResponseType
指定为Brand
的结构的示例,这是一个Codable
结构,表示从服务器返回的品牌数据。
struct BrandRequest: APIRequest { typealias ResponseType = Brand }
struct Brand: Codable { var brandID: Int var brandName: String? }
BrandRequest
用于从服务器获取单个Brand
,但是我也可以获取Brand
的数组(由上面的ArrayResponse
表示,因为Brand是许多不同类型的类型之一都遵循相同的模式),使用BrandsRequest
,将ResponseType
指定为Brand
s的数组。
struct BrandsRequest: APIRequest { typealias ResponseType = [Brand] }
而不是在每个遵循
decode
的结构中提供APIRequest
函数,我决定在协议扩展中进行默认实现,因为它们都遵循相同的解码。
取决于ResponseType
是数组(例如[Brand]
,还是单个项目,例如Brand
,我使用了另一个版本的decode
函数。这对于单个项目效果很好,但是对于项目数组,我想研究一下Array,发现其元素的类型,并使用它来检查result.decoded()
是否被解码为该特定类型的ArrayResponse<>
。
因此,例如,如果我创建一个BrandsRequest
,我想要这个顶部的decode
函数,该函数对数组进行解码以返回(try result.decoded() as ArrayResponse<Brand>).items
,而Brand
是一个不同的结构(例如Product
,[C0 ]等),具体取决于此函数接收的数组中Element的类型。此示例包含一些未编译的代码,作为我尝试获取Customer
并将其用作通用参数的方法,但是当然不起作用。我也不能简单地将elementType
作为通用参数传递,因为编译器告诉我:Codable
。
所以我的问题是:
Value of protocol type 'Codable' (aka 'Decodable & Encodable') cannot conform to 'Decodable'; only struct/enum/class types can conform to protocols
中使用的元素的类型?ArrayResponse<insert type here>
返回类似于decode
的项的数组的网络响应与ArrayResponse
的单个项的响应?Brand
附录:我想到的另一种方法是更改extension APIRequest where ResponseType == Array<Codable> {
func decode(_ result: Result<Data, APIError>) throws -> ResponseType {
let elementType = type(of: ResponseType.Element.self)
print(elementType)
return (try result.decoded() as ArrayResponse<elementType>).items
}
}
extension APIRequest {
func decode(_ result: Result<Data, APIError>) throws -> ResponseType {
return try result.decoded() as ResponseType
}
}
以使用T作为数组类型,而不是元素类型:
ArrayResponse<>
然后像这样简化数组解码:
struct ArrayResponse<T>: Codable where T: Codable { let items: T let totalItems: Int }
但是,编译器给了我这两个错误:
extension APIRequest where ResponseType == Array<Codable> { func decode(_ result: Result<Data, APIError>) throws -> ResponseType { return (try result.decoded() as ArrayResponse<ResponseType>).items } }
和'ArrayResponse' requires that 'Decodable & Encodable' conform to 'Encodable'
附录2:
如果将另一个关联类型添加到Value of protocol type 'Decodable & Encodable' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols
以定义数组中Element的类型,则可以使所有工作正常进行和编译:APIRequest
然后将我的数组
protocol APIRequest { associatedtype ResponseType: Codable associatedtype ElementType: Codable /// Decodes the request result into the ResponseType func decode(_: Result<Data, APIError>) throws -> ResponseType }
更改为使用decode
而不是ElementType
:
Codable
但是我必须在每个符合
extension APIRequest where ResponseType == Array<ElementType> { func decode(_ result: Result<Data, APIError>) throws -> ResponseType { return (try result.decoded() as ArrayResponse<ResponseType>).items } }
的结构中提供ElementType
,包括对APIRequest
多余且未使用的单个请求。对于数组请求,它只是数组ResponseType
内的值,也感觉重复:
ResponseType
我的问题的症结在于,我想在
struct BrandRequest: APIRequest { typealias ResponseType = Brand typealias ElementType = Brand } struct BrandsRequest: APIRequest { typealias ResponseType = [Brand] typealias ElementType = Brand }
数组中发现Brand
类型,并将其用于[Brand]
解码。
我有一个名为APIRequest的协议,其关联类型为ResponseType和一个解码函数。这个例子并不完整,但是我相信这些是问题的唯一相关部分。 ...
可能值得创建ArrayResponse
,然后提供ArrayRequest
的默认实现,例如:
我怀疑这是对协议的滥用。 PAT(具有关联类型的协议)都是为了向现有类型添加更多功能,目前尚不清楚这样做。相反,我认为您有一个泛型问题。