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

如何用Rust+Serde反序列化含不同内容的枚举类型?

Rust+Serde反序列化混合单字符串与多语言表的枚举方案

你有如下格式的TOML文件,其中值要么是普通字符串,要么是包含多语言翻译的表:

a = "Hi"
b = { en = "Hello", de = "Hallo" }

最初尝试的Serde反序列化代码无法正常工作,报错提示wanted exactly 1 element, more than 1 element,原代码如下:

use serde::{self, Deserialize};

#[derive(Debug, Deserialize)]
struct MultiLangString {
    de: Option<String>,
    en: Option<String>,
}

#[derive(Debug, Deserialize)]
enum LangString {
    SingleLang(String),
    MultiLang(MultiLangString),
}

解决方案

问题出在Serde默认的枚举反序列化规则——它期望枚举值带有明确的标签(如{"SingleLang": "Hi"}),但你的TOML里是直接的原始字符串或表结构。解决方法是给LangString枚举添加#[serde(untagged)]属性,让Serde自动尝试将输入匹配到合适的枚举变体:

use serde::{Deserialize};
use toml;

#[derive(Debug, Deserialize)]
struct MultiLangString {
    de: Option<String>,
    en: Option<String>,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)] // 关键属性
enum LangString {
    SingleLang(String),
    MultiLang(MultiLangString),
}

// 测试示例
fn main() -> Result<(), toml::de::Error> {
    let toml_content = r#"
a = "Hi"
b = { en = "Hello", de = "Hallo" }
"#;

    #[derive(Debug, Deserialize)]
    struct Config {
        a: LangString,
        b: LangString,
    }

    let config: Config = toml::from_str(toml_content)?;
    println!("{:#?}", config);
    Ok(())
}

原理说明

#[serde(untagged)]告诉Serde不要期望枚举有外部标签,而是依次尝试将输入反序列化为每个枚举变体:

  1. 对于普通字符串,会匹配SingleLang(String)变体;
  2. 对于包含en/de字段的表,会匹配MultiLang(MultiLangString)变体;
  3. 如果所有变体都匹配失败,才会抛出反序列化错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:17:40