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

重写UnkeyedDecodingContainer协议方法未被调用,如何解决?

解码自定义Money类型时UnkeyedDecodingContainer扩展方法不被调用的问题

已正常工作的KeyedDecodingContainer扩展

以下扩展KeyedDecodingContainer的代码可以正常将JSON字符串解码为Money类型:

extension KeyedDecodingContainer {
    func decode(_: Money.Type, forKey key: Key) throws -> Money {
        let str = try decode(String.self, forKey: key)
        return try str.toMoney(on: key)
    }
    
    func decodeIfPresent(_: Money.Type, forKey key: Key) throws -> Money? {
        let str = try decodeIfPresent(String.self, forKey: key)
        return try str?.toMoney(on: key)
    }
}

无法生效的UnkeyedDecodingContainer扩展

为了解码[Money]数组,我尝试对UnkeyedDecodingContainer做类似扩展,但这些重写的方法从未被调用:

extension UnkeyedDecodingContainer {
    mutating func decode(_: Money.Type) throws -> Money {
        let str = try decode(String.self)
        return try str.toMoney()
    }
    
    mutating func decodeIfPresent(_: Money.Type) throws -> Money? {
        let str = try decodeIfPresent(String.self)
        return try str?.toMoney()
    }
}

问题分析与限制

  • 我推测问题核心在于KeyedDecodingContainer是结构体,而UnkeyedDecodingContainer是协议,导致扩展方法无法被正确分发调用。
  • 标准做法是扩展Money实现自定义Decodable的init(from:),但我无法这么做:Money已经遵循Decodable协议,且已有默认实现(期望从Double而非String解码),无法重写该方法。

最小可复现代码

Money是第三方库类型的别名:

typealias Money = Dollars<Double>

String的扩展方法,用于将字符串转为Money:

extension String {
    func toMoney(on key: CodingKey? = nil) throws -> Money {
        if let money = Money(self) { return money }
        throw DecodingError.dataCorrupted(.init(
            codingPath: key.map { [$0] } ?? [],
            debugDescription: "Can't convert JSON String to Money"
        ))
    }
}

使用示例

struct PriceData: Decodable {
    let price: Money?
    let prices: [Money]
}

// 注意:JSON中的值是字符串类型
let jsonData = """
{
    "price": "10.5",
    "prices": ["5.3", "7.1", "9.6"]
}
""".data(using: .utf8)!

do {
    let coin = try JSONDecoder().decode(PriceData.self, from: jsonData)
    print("Price: ", coin.price)
    print("Prices: ", coin.prices)
} catch {
    print("Error decoding JSON: \(error)")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:44:51