在这里,我有一个用于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
类型?
我已尝试执行以下操作,但没有任何效果
Void
以Codable
Result: Void
extension Response: Codable where Result: Codable {}
extension Response: Codable where Result: Void {}
Never
也不会工作,因为它没有自己的初始化程序,因此我无法使其符合 Codable
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
类型的方法。为此。
您可以这样定义您的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
,在需要结果的情况下,您可以保持常规解码,并且可以使其保持非可选状态。
我以为这会导致崩溃,但是确实有效。我尝试使用扩展名执行此操作
extension Response where Result: Nothing
,extension Response
但没有成功。