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

如何正确重新编码时而为对象时而为数组的坐标类型?

保留坐标原始编码格式的实现方案

针对你需要将坐标按原始解码时的格式(对象/数组)重新编码的需求,结合你提到的API新旧格式并存、编码规则明确的场景,这里提供两种可行方案:

方案一:记录原始编码类型(轻量首选)

在Coordinates结构体中新增私有属性记录解码时识别到的原始格式,编码时根据该值匹配对应逻辑,这是改动最小、最直接的实现方式。

具体实现

  1. 给Coordinates结构体添加格式标记属性:
struct Coordinates<Element: Codable> {
    var x: Element
    var y: Element?
    var z: Element
    
    // 私有枚举标记原始编码格式
    private enum OriginalFormat {
        case object
        case array
    }
    private var originalFormat: OriginalFormat
}
  1. 修改解码逻辑,成功解码时同步设置格式标记,新增编码逻辑匹配原始格式:
extension Coordinates : Codable {
    private enum CodingKeys : String, CodingKey {
        case x
        case y
        case z
    }
    
    init(from decoder : Decoder) throws {
        if let container = try? decoder.container(keyedBy: CodingKeys.self) {
            self.x = try container.decode(Element.self, forKey: .x)
            self.y = try container.decodeIfPresent(Element.self, forKey: .y)
            self.z = try container.decode(Element.self, forKey: .z)
            self.originalFormat = .object
        } else if var container = try? decoder.unkeyedContainer() {
            self.x = try container.decode(Element.self)
            self.z = try container.decode(Element.self)
            
            if let z = try? container.decode(Element.self) {
                self.y = self.z
                self.z = z
            }
            self.originalFormat = .array
        } else {
            preconditionFailure("Cannot decode coordinates")
        }
    }
    
    // 根据原始格式选择编码方式
    func encode(to encoder: Encoder) throws {
        switch originalFormat {
        case .object:
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(x, forKey: .x)
            try container.encodeIfPresent(y, forKey: .y)
            try container.encode(z, forKey: .z)
        case .array:
            var container = encoder.unkeyedContainer()
            try container.encode(x)
            // 兼容数组的2元素/3元素场景
            if let y = y {
                try container.encode(y)
                try container.encode(z)
            } else {
                try container.encode(z)
            }
        }
    }
}

这个方案的优势:

  • 无需拆分现有结构体,代码改动量极小
  • 逻辑直观,完全匹配“解码记格式、编码复用格式”的需求
  • 适配你当前API新旧格式并存的场景

方案二:协议+多结构体实现(类型化区分)

如果希望从类型层面直接区分两种格式的坐标,可以定义Coordinates协议,分别实现对象格式和数组格式的结构体。

具体实现

  1. 定义通用协议:
protocol Coordinates: Codable {
    associatedtype Element: Codable
    var x: Element { get set }
    var y: Element? { get set }
    var z: Element { get set }
}
  1. 实现两种格式的结构体:
// 对象格式坐标
struct StructuredCoordinates<Element: Codable>: Coordinates {
    var x: Element
    var y: Element?
    var z: Element
    
    private enum CodingKeys: String, CodingKey {
        case x, y, z
    }
}

// 数组格式坐标
struct ArrayCoordinates<Element: Codable>: Coordinates {
    var x: Element
    var y: Element?
    var z: Element
    
    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        self.x = try container.decode(Element.self)
        self.z = try container.decode(Element.self)
        
        if let z = try? container.decode(Element.self) {
            self.y = self.z
            self.z = z
        }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        try container.encode(x)
        if let y = y {
            try container.encode(y)
            try container.encode(z)
        } else {
            try container.encode(z)
        }
    }
}
  1. 辅助解码方法,根据格式实例化对应结构体:
func decodeCoordinates<Element: Codable>(from data: Data) throws -> any Coordinates where Element == Element.Element {
    do {
        return try JSONDecoder().decode(StructuredCoordinates<Element>.self, from: data)
    } catch {
        return try JSONDecoder().decode(ArrayCoordinates<Element>.self, from: data)
    }
}

这个方案的优势:

  • 类型语义清晰,不同格式的坐标是独立类型
  • 编码逻辑完全隔离,各自维护自身规则
  • 适合未来格式可能进一步扩展的场景

方案选择建议

结合你的场景(事先知晓编码格式、API新旧格式并存),**方案一(记录原始类型)**是最优选择,它不需要改动现有结构体的使用方式,代码成本极低,完全满足需求。如果未来需要对两种格式做更多差异化处理,再考虑切换到方案二。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 12:54:17