You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Codable如何编码包装类型避免容器中产生JSON嵌套

问题描述

常规场景下定义如下结构体:

struct Box: Codable {
  let id: String

  /// 该字段为表达式(例如 `x + 3`),而非普通数值
  let height: String
}

编码后输出的JSON格式为:

{
  "id": "box1",
  "height": "x + 3"
}

为了明确标识height字段不能传入普通字符串,现在引入新的包装类型Expression,修改后的代码如下:

struct Box: Codable {
  let id: String
  let height: Expression
}

struct Expression: Codable {
  let string: String
}

引入包装类型后API语义更清晰,但编码生成的JSON出现了不必要的嵌套:

{
  "id": "box1",
  "height": {
    "string": "x + 3"
  }
}

需要消除这层嵌套,让编码结果恢复为扁平化结构:

{
  "id": "box1",
  "height": "x + 3"
}

实现约束

不能重写Box类型的任何Codable相关逻辑,原因如下:

  • Box可能包含大量其他属性,手动维护encode/decode函数的维护成本过高
  • 所有使用Expression类型的场景都应自动复用无嵌套的编码行为,无需重复编写Codable样板代码

也就是说需求范围限定为:仅修改Expression类型的实现,使其编码输出时不引入额外的容器层级。

此前尝试过使用container.superEncoder()实现,但该方法仅会将嵌套键名从"string"修改为"super",层级嵌套的问题并未解决。


实现方案

给Expression实现自定义Codable逻辑,使用单值容器替代默认的键值容器即可,代码如下:

struct Expression: Codable {
  let string: String

  init(from decoder: Decoder) throws {
    let container = try decoder.singleValueContainer()
    string = try container.decode(String.self)
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.singleValueContainer()
    try container.encode(string)
  }
}

实现原理:系统为结构体自动生成的Codable实现,默认会创建一个键值映射容器,将结构体的所有属性作为嵌套键写入该容器,这就是多余嵌套的来源。而singleValueContainer()会直接在当前编码位置读写原始值,不会额外创建嵌套容器,完全匹配需求。

该实现不需要修改Box的任何代码,所有引用Expression类型的地方都会自动应用扁平化的编解码逻辑,没有额外的重复维护成本。


内容的提问来源于stack exchange,提问作者Senseful

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:15:30