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

如何为Swift Protobuf生成的Message结构体添加通用Codable扩展?

解决方案

1. 利用Swift Protobuf公共协议做条件扩展

Swift Protobuf生成的所有消息类型都遵循SwiftProtobuf.Message公共协议,我们可以基于这个协议编写条件扩展,为所有符合条件的类型提供Codable的默认实现,彻底避免重复编写样板代码:

import SwiftProtobuf

// 给所有遵循SwiftProtobuf.Message且同时遵循Codable的类型,提供Codable默认实现
extension SwiftProtobuf.Message where Self: Codable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let data = try container.decode(Data.self)
        self = try Self(serializedData: data)
    }
    
    public func encode(to encoder: Encoder) throws {
        let data = try self.serializedData()
        var container = encoder.singleValueContainer()
        try container.encode(data)
    }
}

之后,你只需要给每个生成的消息类型添加一行声明即可,无需重复编写实现:

extension Message1: Codable {}
extension Message2: Codable {}

2. 用标记协议简化声明(可选)

如果觉得每个类型加一行还是繁琐,可以定义一个标记协议整合Codable和SwiftProtobuf.Message,再给这个协议提供默认实现:

import SwiftProtobuf

// 定义标记协议
protocol ProtobufCodable: Codable, SwiftProtobuf.Message {}

// 给标记协议提供Codable默认实现
extension ProtobufCodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let data = try container.decode(Data.self)
        self = try Self(serializedData: data)
    }
    
    public func encode(to encoder: Encoder) throws {
        let data = try self.serializedData()
        var container = encoder.singleValueContainer()
        try container.encode(data)
    }
}

然后给每个消息类型添加标记协议的遵循声明:

extension Message1: ProtobufCodable {}
extension Message2: ProtobufCodable {}

3. 进阶:用代码生成工具完全自动化

如果项目中有大量Protobuf消息类型,手动添加扩展声明也麻烦,可以用Sourcery这类代码生成工具自动完成:

  1. 编写Sourcery模板文件(比如ProtobufCodable.stencil):
{% for type in types.based.SwiftProtobuf.Message %}
extension {{ type.name }}: Codable {}
{% endfor %}
  1. 配置Sourcery扫描你的Protobuf生成代码目录,它会自动为所有SwiftProtobuf.Message类型生成Codable扩展声明,结合第一步的条件扩展,实现完全无样板代码。

关于泛型扩展的说明

Swift不允许直接通过泛型扩展让类型遵循新协议(比如extension<T: SwiftProtobuf.Message> T: Codable这种语法是非法的),但我们可以通过条件协议扩展(即上面用到的where Self: Codable)来为符合条件的类型提供默认实现,再通过简单的扩展声明让类型正式遵循Codable,这是当前最简洁的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:53:10