如何编写使用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
相关产品推荐
相关产品推荐

