swift - 对泛型结构数组进行编码
问题描述
我正在尝试进行一个 API 调用,该调用采用 JSON 请求主体,如下所示:
[
{ "op": "replace", "path": "/info/name", "value": "TestName" },
{ "op": "replace", "path": "/info/number", "value": 100 },
{ "op": "replace", "path": "/info/location", "value": ["STATE", "CITY"] },
{ "op": "replace", "path": "/privacy/showLocation", "value": true }
]
我有一些op
和path
值的枚举:
enum ChangeOp: String, Encodable {
case replace
case append
}
enum ChangePath: String, Encodable {
case name = "/info/name"
case number = "/info/number"
case location = "/info/location"
case showLocation = "/privacy/showLocation"
}
在这个答案中,我发现您必须使用协议来创建通用结构数组,所以我有以下协议和结构:
protocol UserChangeProto {
var op: ChangeOp { get }
var path: ChangePath { get }
}
struct UserChange<ValueType: Encodable>: Encodable, UserChangeProto {
let op: ChangeOp
let path: ChangePath
let value: ValueType
}
这是编码发生的地方:
func encodeChanges(arr: [UserChangeProto]) -> String? {
let encoder = JSONEncoder()
guard let jsonData = try? encoder.encode(arr) else {
return nil
}
return String(data: jsonData, encoding: String.Encoding.utf8)
}
func requestUserChanges(changes: String) {
print(changes)
// make API request ...
}
requestUserChanges(changes:
encodeChanges(arr: [
UserChange(op: .replace, path: .name, value: "TestName"),
UserChange(op: .replace, path: .number, value: 100),
UserChange(op: .replace, path: .location, value: ["STATE", "CITY"]),
UserChange(op: .replace, path: .showLocation, value: true)
]) ?? "null"
)
问题是当我尝试运行时encoder.encode(arr)
,我收到以下错误:Value of protocol type 'UserChangeProto' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols
.
我的问题是,我怎样才能绕过这个错误?或者换句话说,对泛型结构数组进行编码的最简单方法是什么?
编辑:所以看起来这是Swift 团队正在研究的 Swift 语言本身的问题。我不知道如何在这里进行...
解决方案
您可能会发现类型擦除编码很有用:https ://github.com/Flight-School/AnyCodable
使用上面的 AnyEncodable:
struct Change<V: Encodable>: Encodable {
enum Op: String, Encodable {
case replace
case append
}
enum Path: String, Encodable {
case name = "/info/name"
case number = "/info/number"
case location = "/info/location"
case showLocation = "/privacy/showLocation"
}
var op: Op
var path: Path
var value: V
}
let encoder = JSONEncoder()
let changes: [Change<AnyEncodable>] = [
Change(op: .append, path: .name, value: "Foo"),
Change(op: .replace, path: .number, value: 42)
]
let r = try? encoder.encode(changes)
String(data: r!, encoding: .utf8)
给出你所期望的
推荐阅读
- c# - 将用户定义的对象传递给 IoptionsMonitor
- sql - 具有多对多和计算的 TypeORM 高级查询
- maven - 无法解锁maven镜像块
- perl - 在 Perl 中对结构元素的错误访问
- azure-devops - Azure Devops 计划管道不会触发
- python - 尽管 mypy 很高兴,但通用超类“未定义”
- node.js - 使用 getAmountsOut() ABI 在 ethers.io 库中获取正确的小数
- css - 如何使用 jit 在 tailwind-css 中使用布局变体?
- c# - 如何为我的 ListBox 正确使用绑定以分别为每个项目使用单选按钮选择?
- kubernetes-helm - Helm --根据值设置访问列表项