【发布时间】:2018-07-20 19:24:51
【问题描述】:
简短的问题是,当满足其中任何一个条件时,如何使类型有条件地符合具有两个条件的协议?
我有一个泛型类型NetworkResponse<Data>。它代表服务器响应。这是它的定义方式:
enum NetworkResponse<Data> {
case success(Data)
case error(ServerError)
}
我想让NetworkResponse 符合Decodable。这是我的服务器响应格式:
{
"data": {
"someKey": "someValue",
"anotherKey": 15
},
"meta": {
"returnCode": 0,
"returnMessage": "operation is successful"
}
}
data 部分取决于发出的请求。 meta 部分代表一些关于响应的元数据。就像它是否成功,或者如果不是什么是错误。
这就是我实现Decodable的方法:
extension NetworkResponse: Decodable where Data: Decodable {
enum CodingKeys: CodingKey {
case meta
case data
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let metaValue = try container.decode(ServerError.self, forKey: .meta)
if metaValue.code != 0 {
self = .error(metaValue)
} else {
self = .success(try container.decode(Data.self, forKey: .data))
}
}
}
到目前为止一切顺利。但这是我的问题。对于一些不需要返回任何数据的 API,响应中的data 部分被省略。在这种情况下,我的响应如下所示:
{
"meta": {
"returnCode": 0,
"returnMessage": "operation is successful"
}
}
在这种情况下,我想将响应 json 解码为NetworkResponse<Void>。但是由于Void 不能符合Decodable(因为它是非标称类型)编译器给出错误。
为了克服这个问题,我尝试创建更专业的Decodable 扩展,其中Data 是Void,如下所示:
extension NetworkResponse: Decodable where Data == Void {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let metaValue = try container.decode(AppErrors.Server.self, forKey: CodingKeys.meta)
if metaValue.code != 0 {
self = .error(metaValue)
} else {
self = .success(())
}
}
}
但编译器仍然编译如:Conflicting conformance of 'NetworkResponse<Data>' to protocol 'Decodable'; there cannot be more than one conformance, even with different conditional bounds。
那么当Data 是Void 时,如何创建单独的init(from:) 函数?
【问题讨论】:
-
我相信
Data应该是可选的?其他选项可以是添加另一个成功的枚举案例。
标签: json swift generics protocols decodable