21

我有一个通用的 REST 请求:

struct Request<T> {…}

是请求的T返回类型,例如:

struct Animal {…}
let animalRequest = Request<Animal>
let animal: Animal = sendRequest(animalRequest)

现在我想表达泛型类型必须符合,Decodable以便我可以解码来自服务器的 JSON 响应:

struct Request<T> where T: Decodable {…}
struct Animal: Decodable {…}

这是有道理且有效的——直到我收到一个没有响应的请求,一个Request<Void>. 编译器对此不满意:

Type 'Void' does not conform to protocol 'Decodable'

编译器很快发现了我通过添加Decodable一致性来解决这个问题的恶作剧:Void

extension Void: Decodable {…} // Error: Non-nominal type 'Void' cannot be extended

让请求泛型而不是返回类型感觉是正确的。有没有办法让它与Void返回类型一起工作?(例如,只是在服务器上创建一些东西而不返回任何东西的请求。)

4

2 回答 2

29

一个简单的解决方法是引入一个自定义的“no-reply”类型来替换Void

struct NoReply: Decodable {}

符合VoidDecodable不可能的。Void只是空元组的类型别名(), 和元组目前不能符合协议,但它们最终会。

于 2017-08-11T14:02:16.017 回答
0

我发现有时其他类型的其他编码对象可以解码为 NoReply.self。例如自定义错误类型(枚举)即可。

本案例的游乐场示例:

enum MyError: String, Codable {
    case general
}

let voidInstance = VoidResult()
let errorInstance = MyError.general
let data1 = try! JSONEncoder().encode(voidInstance)
let data2 = try! JSONEncoder().encode(errorInstance)

let voidInstanceDecoded = try! JSONDecoder().decode(VoidResult.self, from: data1)
//VoidResult as expected

let errorInstanceDecoded = try! JSONDecoder().decode(MyError.self, from: data2)
//MyError.general as expected

let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//VoidResult - NOT EXPECTED

let errorInstanceDecodedFromVoid = try! JSONDecoder().decode(ScreenError.self, from: data1)
//DecodingError.typeMismatch - Expected

所以我的建议是添加“NoReply 的唯一性(zoul 的回答)):

struct VoidResult: Codable {
    var id = UUID()
}

let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//DecodingError.typeMismatch - Now its fine - as expected
于 2020-11-18T19:30:43.693 回答