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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:00:03