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

如何将匿名枚举值序列解析为Rust元组结构体?

如何将JSON数组直接解析为包含枚举向量的元组结构体?

默认情况下,Serde对枚举的反序列化要求每个变体以带键的JSON对象形式存在(比如{"Single": 1}),但要直接解析[1, [2], [[3]]]这类纯JSON数组/数字组成的结构,你可以通过#[serde(untagged)]属性让Serde自动匹配枚举变体,无需额外的键包裹。

修改后的代码

use serde::Deserialize;

#[derive(Deserialize, Debug, PartialEq, Eq)]
#[serde(untagged)] // 添加该属性实现无标签枚举反序列化
enum Data {
    Single(i32),
    List(Vec<Data>),
}

#[derive(Deserialize, Debug, PartialEq, Eq)]
struct Packet(Vec<Data>);

fn main() {
    let packet = r#"[1, [2], [[3]]]"#;

    assert_eq!(
        serde_json::from_str::<Packet>(packet).unwrap(),
        Packet(vec![
            Data::Single(1),
            Data::List(vec![Data::Single(2)]),
            Data::List(vec![Data::List(vec![Data::Single(3)])])
        ])
    );
}

原理说明

#[serde(untagged)]会让Serde放弃对枚举变体的标签校验,转而按变体定义的顺序尝试匹配输入的JSON值:

  • 遇到JSON数字时,自动匹配Single(i32)变体;
  • 遇到JSON数组时,自动匹配List(Vec<Data>)变体;
  • 若输入值无法匹配任何变体,会返回反序列化错误。

手动实现反序列化(可选,用于精细控制)

如果需要更灵活的逻辑,也可以手动实现Deserialize trait:

use serde::{de, Deserialize, Deserializer};
use std::fmt;

#[derive(Debug, PartialEq, Eq)]
enum Data {
    Single(i32),
    List(Vec<Data>),
}

impl<'de> Deserialize<'de> for Data {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct DataVisitor;

        impl<'de> de::Visitor<'de> for DataVisitor {
            type Value = Data;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a number or an array of Data")
            }

            fn visit_i32<E>(self, value: i32) -> Result<Data, E>
            where
                E: de::Error,
            {
                Ok(Data::Single(value))
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Data, A::Error>
            where
                A: de::SeqAccess<'de>,
            {
                let mut vec = Vec::new();
                while let Some(element) = seq.next_element()? {
                    vec.push(element);
                }
                Ok(Data::List(vec))
            }
        }

        deserializer.deserialize_any(DataVisitor)
    }
}

#[derive(Deserialize, Debug, PartialEq, Eq)]
struct Packet(Vec<Data>);

fn main() {
    let packet = r#"[1, [2], [[3]]]"#;

    assert_eq!(
        serde_json::from_str::<Packet>(packet).unwrap(),
        Packet(vec![
            Data::Single(1),
            Data::List(vec![Data::Single(2)]),
            Data::List(vec![Data::List(vec![Data::Single(3)])])
        ])
    );
}

这种方式通过自定义Visitor,明确处理JSON数字和数组两种输入格式,将其分别映射到对应的枚举变体。

内容的提问来源于stack exchange,提问作者Paweł Rubin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 03:01:00