如何避免在将来修改枚举变体时破坏序列化数据?

huangapple go评论66阅读模式
英文:

How to avoid breaking serialized data where enum variants are going to be modified in the future?

问题

使用Bincode进行序列化,数据包含一个类似这样的enum

enum E {
   A = 0,
   B = 1,
   C = 2,
}

变体E::A从未被使用,所以我认为移除它不会引发问题:

enum E {
   B = 1,
   C = 2,
}

显然,序列化器不关心显式的判别值:

// 反序列化错误:
"invalid value: integer `2`, expected variant index 0 <= i < 2"

是否有办法使"Bincode"使用显式的判别值?或者是否有更合适的解决方案?

谢谢。

英文:

Serializing with Bincode, data contains an enum like this:

enum E {
   A = 0,
   B = 1,
   C = 2,
}

The variant E::A was never used, so I thought removing it wouldn't cause a problem:

enum E {
   B = 1,
   C = 2,
}

Apparently the serializer does not care about explicit discriminants:

// deser error:
&quot;invalid value: integer `2`, expected variant index 0 &lt;= i &lt; 2&quot;

Is there a way to make "Bincode" use the explicit discriminants? Or is there a more proper solution?

Thanks.

答案1

得分: 1

serde派生宏在序列化枚举时使用变体的索引或名称(由格式选择)。Bincode选择索引。

只要您的枚举完全由单元变体组成,您可以使用serde_repr来表示为u32

use serde_repr::{Deserialize_repr, Serialize_repr};

#[derive(Deserialize_repr, Serialize_repr)]
#[repr(u32)]
enum E1 {
    A = 0,
    B = 1,
    C = 2,
}

#[derive(Deserialize_repr, Serialize_repr)]
#[repr(u32)]
enum E2 {
    B = 1,
    C = 2,
}

这些也可以与具有serde派生的枚举在bincode中兼容:

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
enum E1 {
    A,
    B,
    C,
}

请注意,这会覆盖在人类可读格式中使用的变体名称。如果您还要将其序列化为人类可读格式并希望保留变体名称,或者如果您有带有数据的变体,您将需要编写自定义的DeserializeSerialize实现。

相关问题,我刚刚回答过:如何在Rust中使用Bincode序列化枚举时保留枚举标志而不是索引? 由于u64标签,这个问题最终变得完全不同,但它包含了有关枚举序列化的各个部分由哪些库负责的大量信息。

英文:

The serde derive macros use the variant's index or name (chosen by the format) when serializing an enum. Bincode chooses the index.

As long as your enum is composed entirely of unit variants, you can use serde_repr with a u32 representation.

use serde_repr::{Deserialize_repr, Serialize_repr};

#[derive(Deserialize_repr, Serialize_repr)]
#[repr(u32)]
enum E1 {
    A = 0,
    B = 1,
    C = 2,
}

#[derive(Deserialize_repr, Serialize_repr)]
#[repr(u32)]
enum E2 {
    B = 1,
    C = 2,
}

These will also be compatible in bincode specifically with an enum with serde derives:

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
enum E1 {
    A,
    B,
    C,
}

Note that this overrides the variant names used in human-readable formats. If you are also serializing to a human-readable format and want to preserve the variant names, or if you have variants with data, you will need to write custom Deserialize and Serialize implementations.

Related question that I just answered: How to Serialize Enum in Rust with Bincode While Retaining Enum Discriminant Instead of Index? This one ended up being completely different because of the u64 tags, but it has lots of information on which libraries are responsible for each part of enum serialization.

huangapple
  • 本文由 发表于 2023年7月11日 11:52:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76658610.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定