使用Swift 4的可解码解码Void

时间:2017-08-11 12:15:51

标签: json swift decodable

我有一个通用的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返回类型一起使用? (例如,只在服务器上创建内容并且不返回任何内容的请求。)

2 个答案:

答案 0 :(得分:15)

一个简单的解决方法是引入一个替换Void的自定义“无回复”类型:

struct NoReply: Decodable {}

可以使Void符合DecodableVoid只是空元组()的类型别名,而元组此时无法符合协议,但最终将会符合协议。

答案 1 :(得分:0)

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

这种情况的操场示例:

arr = [("cluster_comp_444", "Home equipment & interior design"), \
  ("cluster_comp_1160", "Going Out & shows"), \
  ("cluster_comp_217576624", "Healthcare & medicine"), \
  ("cluster_comp_465", "Good deals")]

df = spark.createDtaFrame(arr)    
dic = {row[0]:row[1] for row in df.collect()}

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

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