【发布时间】:2021-12-15 15:22:10
【问题描述】:
我想在我的结构中添加一个简单的版本方案 + 检查:
#[derive(Serialize, Deserialize)]
struct Versioned {
version: u32,
other_field: String,
}
impl Versioned {
const FORMAT_VERSION: u32 = 42;
}
这个想法相当简单:version 字段被反序列化(如果不存在,则为 0*),如果不等于 FORMAT_VERSION,则会引发错误。然后,处理结构的其余部分。这里的顺序很重要:否则,反序列化错误可能不正确(您可能会得到类似“缺少字段new_field”而不是“版本太旧”)。
我尝试了一些关于包装器类型和自定义反序列化器的想法,但都没有提供良好的用户体验。到目前为止我最好的:
#[derive(Serialize, Deserialize)]
struct Payload {
some_field: String,
}
#[derive(Serialize, Deserialize)]
#[serde(tag = "version")]
enum Versioned {
#[serde(rename = "0")]
Inner(Payload),
}
它使用枚举包装器进行版本检查,并使用两个From 实现来轻松进行类型转换。缺点是:
- 该字段*没有默认值(= 不向后兼容未版本化的数据)
- 旧版本上的错误消息(“错误:未知变体
42,预期0在第 2 行第 17 列”而不是“无效版本”之类的内容)
* 注意:向后兼容性要求使事情变得更加困难。所以请记住,请务必立即为您的所有数据添加 version 字段!
【问题讨论】:
-
@JeroenVervaeke 因为我 90% 的用例都是 JSON 序列化,这很好,尽管我更喜欢更通用的解决方案。 (不过取决于自描述数据格式也可以)