基于serde与bincode实现无tag枚举的自定义序列化/反序列化方案
错误原因
#[serde(untagged)]的反序列化逻辑要求序列化格式自带类型描述能力,才能自动匹配枚举变体。但bincode是无自描述信息的二进制格式,不支持该特性,因此抛出DeserializeAnyNotSupported错误。
解决方法
移除#[serde(untagged)]和默认派生的序列化/反序列化实现,手动按照你的业务规则实现Serialize和Deserialize trait,完整可运行代码如下:
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::de::Error as DeError; use bincode::{DefaultOptions, Options}; #[derive(Debug, PartialEq)] enum Command { Operation(u8), Element(Vec<u8>) } impl Serialize for Command { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { match self { // Operation直接序列化u8值 Command::Operation(v) => serializer.serialize_u8(*v), // Element直接序列化Vec<u8>(bincode会先写长度再写内容) Command::Element(v) => v.serialize(serializer), } } } impl<'de> Deserialize<'de> for Command { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { // 先读取第一个字节判断类型 let first_byte: u8 = Deserialize::deserialize(deserializer)?; if first_byte >= 100 { // 大于等于100为Operation类型 Ok(Command::Operation(first_byte)) } else { // 小于100为Element的长度前缀,读取对应数量的字节 let mut content = Vec::with_capacity(first_byte as usize); for _ in 0..first_byte { content.push(Deserialize::deserialize(deserializer)?); } Ok(Command::Element(content)) } } } fn main() { let commands: Vec<Command> = vec![Command::Operation(150), Command::Operation(175), Command::Element(b"123".to_vec())]; let bytes = DefaultOptions::new() .with_varint_encoding() .serialize(&commands).unwrap(); println!("{:?}", bytes); let deserialize_commands: Vec<Command> = DefaultOptions::new() .with_varint_encoding() .deserialize(&bytes[..]).unwrap(); println!("{:?}", deserialize_commands); // 校验反序列化结果和原始值一致 assert_eq!(commands, deserialize_commands); }
运行后输出符合预期:
[3, 150, 175, 3, 49, 50, 51] [Operation(150), Operation(175), Element([49, 50, 51])]
边界说明
- 请确保业务中
Element的长度永远小于100,否则会被误识别为Operation,如果长度可能超过99,需要调整规则适配。 - 该实现匹配
with_varint_encoding配置:100以内的整数varint编码只占1字节,完全符合你读取第一个字节判断类型的逻辑。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

