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

如何让Serde正确将JSON反序列化为指定Rust枚举类型?

解决Serde反序列化Rust枚举时的变体匹配问题

你遇到的问题是Serde默认将所有字符串类型的JSON值都解析为带字符串参数的Pass变体,而没有匹配到Fail和Absent单元变体。这个需求完全可以实现,下面提供两种可行方案:

方案一:使用Serde内置属性快速解决

通过给枚举添加Serde属性,指定变体名称与JSON字符串的映射关系,并将未匹配的字符串统一解析为Pass变体:

use serde::Deserialize;
use serde_json::Error;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")] // 确保变体名称与JSON小写字符串匹配
enum TestResult {
    Fail,
    Absent,
    #[serde(other)] // 所有不匹配前面变体的字符串都解析为Pass
    Pass(String),
}

fn main() -> Result<(), Error> {
    // 测试"fail"解析为Fail变体
    let json_fail = "\"fail\"";
    let result_fail: TestResult = serde_json::from_str(json_fail)?;
    println!("{:?}", result_fail); // 输出: Fail

    // 测试"absent"解析为Absent变体
    let json_absent = "\"absent\"";
    let result_absent: TestResult = serde_json::from_str(json_absent)?;
    println!("{:?}", result_absent); // 输出: Absent

    // 测试普通字符串解析为Pass变体
    let json_pass = "\"test_passed\"";
    let result_pass: TestResult = serde_json::from_str(json_pass)?;
    println!("{:?}", result_pass); // 输出: Pass("test_passed")

    Ok(())
}

关键说明

  • #[serde(rename_all = "snake_case")]:自动将枚举变体名称转换为小写蛇形命名,确保Fail对应JSON中的"fail",Absent对应"absent"。
  • #[serde(other)]:标记Pass变体为"兜底"选项,任何不匹配前面单元变体的字符串都会被解析为该变体的参数。

方案二:自定义反序列化逻辑(更灵活)

如果需要更精细的匹配规则(比如区分大小写、处理特殊字符串),可以实现自定义的反序列化逻辑:

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

#[derive(Debug)]
enum TestResult {
    Fail,
    Absent,
    Pass(String),
}

impl<'de> Deserialize<'de> for TestResult {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // 定义自定义Visitor处理字符串解析
        struct TestResultVisitor;

        impl<'de> Visitor<'de> for TestResultVisitor {
            type Value = TestResult;

            // 提示预期的输入格式
            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a string representing test result")
            }

            // 处理字符串类型的JSON值
            fn visit_str<E>(self, value: &str) -> Result<TestResult, E>
            where
                E: de::Error,
            {
                match value {
                    "fail" => Ok(TestResult::Fail),
                    "absent" => Ok(TestResult::Absent),
                    // 其他所有字符串都转为Pass变体
                    s => Ok(TestResult::Pass(s.to_string())),
                }
            }
        }

        // 告诉Deserializer使用自定义Visitor解析字符串
        deserializer.deserialize_str(TestResultVisitor)
    }
}

// 测试逻辑与方案一一致

这种方式完全由你控制匹配规则,适合复杂场景的需求。

内容的提问来源于stack exchange,提问作者Subhrajyoti Das

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:46:20