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

如何编写使用Type Packs的Codable类型并修复编码键错误?

问题:Swift类型包(Type Pack)相关的Decodable解码错误

我在解析Neo4J数据库HTTP Query API返回的JSON数据,返回格式如下:

{
    "data": {
        "fields": ["column1", "column2"],
        "values": [
            ["value 1", { "property": 1 }],
            ["value 2", { "property": 2 }],
        ]
    }
}

其中values是二维数组,存储查询返回的行,内层数组元素类型异构(因查询列类型不同)。针对每个请求,我清楚内层数组的元素数量和类型,因此尝试用带类型包的Decodable结构体来解码:

public struct NJQueryResponse<each Result: Decodable & Sendable>: Decodable, Sendable {
    public let data: Data
    public struct Data: Decodable, Sendable {
        public let fields: [String]
        public var rows: [(repeat each Result)]
        
        enum CodingKeys: CodingKey {
            case fields, values
        }
        
        public init(from decoder: any Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            fields = try container.decode([String].self, forKey: .fields)
            rows = []
            var rowsContainer = try container.nestedUnkeyedContainer(forKey: .values)
            while !rowsContainer.isAtEnd {
                var rowContainer = try rowsContainer.nestedUnkeyedContainer()
                let row = (repeat try rowContainer.decode((each Result).self))
                rows.append(row)
            }
        }
    }
}

使用时指定类型为NJQueryResponse<String, [String: Int]>即可对应示例JSON,但编译器在CodingKeys枚举处报错:

Enums cannot declare a type pack

明明CodingKeys没有声明类型包,却出现这个错误,该如何修复?


解决方案

错误根源在于:嵌套的Data结构体属于带类型包的外围结构体NJQueryResponse,编译器会错误地将嵌套类型与外围的类型包关联,进而认为CodingKeys枚举也涉及类型包声明(尽管实际上并没有)。

修复方法是将Data结构体从外围结构体中移出,改为独立的泛型结构体,让它直接持有类型包,避免嵌套导致的编译器误判:

public struct NJQueryResponse<each Result: Decodable & Sendable>: Decodable, Sendable {
    public let data: NJQueryResponseData<repeat each Result>
}

public struct NJQueryResponseData<each Result: Decodable & Sendable>: Decodable, Sendable {
    public let fields: [String]
    public var rows: [(repeat each Result)]
    
    enum CodingKeys: CodingKey {
        case fields, values
    }
    
    public init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        fields = try container.decode([String].self, forKey: .fields)
        rows = []
        var rowsContainer = try container.nestedUnkeyedContainer(forKey: .values)
        while !rowsContainer.isAtEnd {
            var rowContainer = try rowsContainer.nestedUnkeyedContainer()
            let row = (repeat try rowContainer.decode((each Result).self))
            rows.append(row)
        }
    }
}

修改后,CodingKeys枚举属于独立的NJQueryResponseData结构体,不再受外围类型包的干扰,编译器能正确识别代码逻辑,错误会消失。使用方式保持不变,依然可以通过NJQueryResponse<String, [String: Int]>来指定行元素的类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 02:50:21