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

Swift中枚举作为字典键解码失败:为何报类型不匹配错误?

问题原因

JSONDecoder默认不支持直接将JSON字典解码为以自定义枚举作为Key的Swift字典。尽管你的枚举是RawRepresentable(基于String类型),但枚举默认的Decodable实现仅用于解码单个枚举值,而非作为字典Key处理,这导致解码器错误地将目标类型识别为数组,进而抛出类型不匹配的错误。

解决方案

方法一:先解码为[String: String]再转换(推荐)

先将JSON解码为基础的字符串键字典,再手动将键转换为枚举类型,这种方式简单直观,适合大多数场景:

enum Lg: String, CaseIterable, Decodable {
    case deutsch = "de"
    case english = "en"
}

let test = "{ \"de\": \"Bisasam\", \"en\": \"Bulbasaur\" }"
let data = test.data(using: .utf8)!
do {
    // 第一步:解码为[String: String]
    let stringDict = try JSONDecoder().decode([String: String].self, from: data)
    // 第二步:转换为[Lg: String],自动过滤无法匹配的键
    let result = Dictionary(uniqueKeysWithValues: stringDict.compactMap { key, value in
        guard let lgKey = Lg(rawValue: key) else {
            // 可选:处理无效键,比如打印日志或抛出错误
            print("忽略无效键:\(key)")
            return nil
        }
        return (lgKey, value)
    })
    print(result) // 输出:[Lg.deutsch: "Bisasam", Lg.english: "Bulbasaur"]
} catch {
    print(error)
}

方法二:自定义字典的Decodable实现(适合频繁使用的场景)

如果你需要频繁解码这种枚举键字典,可以自定义[Lg: String]的Decodable实现,让解码器直接支持该类型:

enum Lg: String, CaseIterable, Decodable {
    case deutsch = "de"
    case english = "en"
}

// 辅助CodingKey类型,用于处理RawRepresentable枚举键
struct RawEnumCodingKey<K: RawRepresentable>: CodingKey where K.RawValue == String {
    let stringValue: String
    let intValue: Int?
    
    init?(stringValue: String) {
        self.stringValue = stringValue
        self.intValue = nil
    }
    
    init?(intValue: Int) {
        return nil
    }
    
    var rawEnum: K? {
        return K(rawValue: stringValue)
    }
}

// 自定义[Lg: String]的Decodable实现
extension Dictionary where Key == Lg, Value == String: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: RawEnumCodingKey<Lg>.self)
        var resultDict = [Lg: String]()
        
        for key in container.allKeys {
            guard let lgKey = key.rawEnum else {
                throw DecodingError.dataCorrupted(.init(
                    codingPath: [key],
                    debugDescription: "无效的语言键:\(key.stringValue)"
                ))
            }
            let value = try container.decode(String.self, forKey: key)
            resultDict[lgKey] = value
        }
        self = resultDict
    }
}

// 使用示例
let test = "{ \"de\": \"Bisasam\", \"en\": \"Bulbasaur\" }"
let data = test.data(using: .utf8)!
do {
    let result = try JSONDecoder().decode([Lg: String].self, from: data)
    print(result)
} catch {
    print(error)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:12:35