如何用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不要期望枚举有外部标签,而是依次尝试将输入反序列化为每个枚举变体:
- 对于普通字符串,会匹配
SingleLang(String)变体; - 对于包含
en/de字段的表,会匹配MultiLang(MultiLangString)变体; - 如果所有变体都匹配失败,才会抛出反序列化错误。
内容的提问来源于stack exchange,提问作者Ilka
相关产品推荐
相关产品推荐

