gpt4 book ai didi

json - Swift 条件符合两种情况

转载 作者:行者123 更新时间:2023-11-28 07:44:28 25 4
gpt4 key购买 nike

简短的问题是,当满足其中一个条件时,如何使类型有条件地符合具有两个条件的协议(protocol)?

我有一个通用类型 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 创建更专业的扩展其中 DataVoid像这样:

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 .

那么我怎样才能创建单独的 init(from:) Data 时使用的函数是Void

最佳答案

我强烈建议您将泛型参数的类型名称从 Data 改掉,因为它很容易与 Swift 中广泛使用的 Foundation.Data 混淆。

关于问题本身,您可以创建一个空结构来表示“void”并向您的 NetworkResponse 添加一个新案例:

struct EmptyData: Decodable {}

enum NetworkResponse<T> {
case success(T)
case successWithEmptyData
case error(ServerError)
}

extension NetworkResponse: Decodable where T: Decodable {
private 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 if T.self == EmptyData.self {
self = .successWithEmptyData
} else {
self = .success(try container.decode(T.self, forKey: .data))
}
}
}

let response = try! JSONDecoder().decode(NetworkResponse<EmptyData>.self, from: jsonData)

或者,您可以让您的 .success 案例包含一个 T? 当您不希望返回任何数据并相应地解码时。

关于json - Swift 条件符合两种情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51449163/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com