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

如何用单个Decodable结构体解码两种键名不同的同结构JSON响应

可以使用单个Struct完成两种响应的解码

核心思路是自定义Decodable的初始化逻辑,为存在键名差异的属性同时兼容两种键名,优先尝试匹配响应2的键,匹配失败时自动降级尝试匹配响应1的对应键即可。

完整实现代码

struct Verse: Decodable, Identifiable {
    let id: Int
    let book_name: String
    let book_id: Int
    let verse: String
    let verse_number: Int
    let chapter: Int // 数据库中的章节ID
    let chapter_number: Int

    // 定义两种响应中所有用到的键名
    enum CodingKeys: String, CodingKey {
        case id, verse, verse_number, chapter
        case book_name, chapter__book__name
        case book_id, chapter__book__id
        case chapter_number, chapter__chapter
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 无差异的字段直接解码
        id = try container.decode(Int.self, forKey: .id)
        verse = try container.decode(String.self, forKey: .verse)
        verse_number = try container.decode(Int.self, forKey: .verse_number)
        chapter = try container.decode(Int.self, forKey: .chapter)
        
        // 有键名差异的字段优先匹配响应2的键,失败则匹配响应1的键
        book_name = try container.decodeIfPresent(String.self, forKey: .book_name) 
            ?? container.decode(String.self, forKey: .chapter__book__name)
        book_id = try container.decodeIfPresent(Int.self, forKey: .book_id) 
            ?? container.decode(Int.self, forKey: .chapter__book__id)
        chapter_number = try container.decodeIfPresent(Int.self, forKey: .chapter_number) 
            ?? container.decode(Int.self, forKey: .chapter__chapter)
    }
}

说明

  • 上述实现对上层业务完全透明,对外暴露的属性命名和你原来的定义完全一致,不需要修改现有调用逻辑
  • 如果后续新增其他键名规则,只需要在CodingKeys中新增对应键,同时在初始化方法中增加对应的降级解码逻辑即可
  • 若存在某个字段在两种响应中都可能为空的场景,可将对应属性修改为可选类型(如let book_name: String?),避免解码失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 17:06:00