英文:
Swift Protobuf Codable Extension
问题
我们在一个项目中使用 Swift Protobuf 生成消息结构体代码(即 DTOs)。它并没有实现 Codable,我正在尝试通过一个扩展(extension)来添加 Codable,以便在非 Protobuf 的情况下使用时可以将它们序列化到磁盘,前提是这些结构体遵循 Codable。然而,为每个结构体都这样做有些模板代码。
除了使用静态的通用方法之外,有没有其他方法来减少这些模板代码?在扩展定义中是否有一种使用泛型的方式来实现这一点?理想情况下,我想用一个通用的扩展来替换 Message1 和 Message2。
在 Swift Protobuf 中,所有消息结构体都应用了一个 Message 扩展,但它们没有一个共同的协议,我可以在扩展的 where 子句中使用。
英文:
We're using Swift Protobuf in a project that generates the message struct code (i.e. DTOs). It doesn't implement Codable and I'm trying to add Codable through an extension so that I can serialize them to disk when used inside a non-protobuf that conforms to Codable. However, it's quite boilerplate to do this for every struct.
Any recommendations on how to minimize the boiler plate code, other than using a static, generic method? Is there a way to do this using generics in the extension definition? Ideally, I'd like to replace Message1 and Message2 with a generic extension.
With Swift Protobuf all message structs have a Message extension applied, but they do not have a common protocol I can use in a where clause for an extension.
extension Message1: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
self = try Message1(serializedData: data)
}
public func encode(to encoder: Encoder) throws {
let data = try self.serializedData()
var container = encoder.singleValueContainer()
try container.encode(data)
}
}
extension Message2: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
self = try Message2(serializedData: data)
}
public func encode(to encoder: Encoder) throws {
let data = try self.serializedData()
var container = encoder.singleValueContainer()
try container.encode(data)
}
}
答案1
得分: 1
首先,声明一个名为CodableMessage的协议,该协议继承自SwiftProtobuf.Message和Codable。使用扩展提供init(from:)和encode(to:)的默认实现。
// 使用这个有限导入以避免导入SwiftProtobuf.Decoder,因为那将与Swift.Decoder冲突并通常很烦人。
import protocol SwiftProtobuf.Message
public protocol CodableMessage: SwiftProtobuf.Message, Codable { }
extension CodableMessage {
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: CodableMessage { }
extension Message2: CodableMessage { }
英文:
First, declare a protocol CodableMessage that refines both SwiftProtobuf.Message and Codable. Use an extension to provide default implementations of init(from:) and encode(to:).
// Use this narrow import to avoid importing SwiftProtobuf.Decoder, since
// that will conflict with Swift.Decoder and generally be annoying.
import protocol SwiftProtobuf.Message
public protocol CodableMessage: SwiftProtobuf.Message, Codable { }
extension CodableMessage {
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)
}
}
Then, extend each of your generated message types to conform to your new protocol:
extension Message1: CodableMessage { }
extension Message2: CodableMessage { }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论