温馨提示:本文翻译自stackoverflow.com,查看原文请点击:swift - Generics that can implement both Void and Codable

swift - 可以同时实现Void和Codable的泛型

发布于 2020-03-27 12:02:22

在这里,我有一个用于api结果的结构

struct Response<Result> {
    let status: Int
    let message: String
    let result: Result
}

现在通常使它符合要求Codable将意味着该Result对象必须是Codable这样做看起来像以下之一

struct Response<Result: Codable>: Codable {...}

// or

extension Response: Codable where Result: Codable {}

我得到的问题是某些响应没有result键,我希望能够Response像使用Void类型一样使用对象,Response<Void>更像是这样

目前,我有一种可能的解决方法,就是这样声明另一个Response没有result变量的类型

struct BaseResponse {
    let status: Int
    let message: String
}

有没有办法避免我不必声明其他Response类型?


我已尝试执行以下操作,但没有任何效果

  1. 我不能符合VoidCodable
  2. 在哪里具有与可编码的另一个扩展一致性 Result: Void
extension Response: Codable where Result: Codable {}

extension Response: Codable where Result: Void {}
  1. Never 也不会工作,因为它没有自己的初始化程序,因此我无法使其符合 Codable
  2. 创建一个Nothing符合Codable这样类型
struct Nothing: Codable, Hashable {
    init() {}

    static var nothing: Nothing { return .init() }
}

所以我可以这样使用响应

let response: Response<Nothing> = Response(
    status: 200,
    message: "Success",
    result: .nothing
)

or

public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.status = try container.decode(forKey: .status)
    self.message = try container.decode(forKey: .message)

    // These lines don't work.
    if let result = try container.decodeIfPresent(Result.self, forKey: .result) {
        self.result = result
    } else {
        self = .nothing
    }
}

但问题是我无法使用decodeIfPresent特定于该Nothing类型方法为此。

查看更多

查看更多

提问者
Zonily Jame
被浏览
102
dan 2019-07-03 23:43

您可以这样定义您的init(from:)方法:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    status = try container.decode(Int.self, forKey: .status)
    message = try container.decode(String.self, forKey: .message)

    if Result.self is Nothing.Type {
        result = Nothing() as! Result
    } else {
        result = try container.decode(Result.self, forKey: .result)
    }
}

您检测到情况确实Response<Nothing>如此,并完全跳过结果的解码。这样result,在需要结果的情况下,您可以保持常规解码,并且可以使其保持非可选状态。