Rust:将JSON解析为复杂枚举时如何减少冗余模式匹配代码
问题原因
默认情况下,serde 反序列化枚举类型时,要求 JSON 结构的外层键为枚举的变体名称,例如要解析为 ResponseFromNetwork::FirstPossibleResponse,对应的 JSON 格式应为:
{ "FirstPossibleResponse": { "first_field": "first_value" } }
而你实际收到的 JSON 是结构体的直接内容,没有外层的变体名包裹,因此直接反序列化枚举时会报错,提示找不到匹配的变体。
解决方案
给枚举添加 #[serde(untagged)] 属性即可实现需求,serde 会自动按枚举变体的定义顺序,尝试将 JSON 内容匹配到对应变体的内部结构体,无需手动编写嵌套匹配逻辑。
修改后的完整代码示例
use serde::Deserialize; use serde_json; #[derive(Deserialize, Debug)] struct FirstPossibleResponse { first_field: String, } #[derive(Deserialize, Debug)] struct SecondPossibleResponse { second_field: String, } // 核心修改:添加untagged属性 #[derive(Deserialize, Debug)] #[serde(untagged)] enum ResponseFromNetwork { FirstPossibleResponse(FirstPossibleResponse), SecondPossibleResponse(SecondPossibleResponse), } impl From<String> for ResponseFromNetwork { fn from(r: String) -> Self { // 无需嵌套匹配,直接反序列化即可 serde_json::from_slice(r.as_bytes()) .unwrap_or_else(|_| unimplemented!("未匹配到已知的响应格式")) } } fn main() { let data_first = r#" { "first_field": "first_value" }"#; let data_second = r#" { "second_field": "first_value" }"#; print!("{:?}", ResponseFromNetwork::from(data_first.to_owned())); print!("{:?}", ResponseFromNetwork::from(data_second.to_owned())); }
注意事项
- 如果不同响应结构体的字段存在重叠,需要把匹配规则更严格、优先级更高的变体放在枚举定义的前面,避免serde提前匹配到错误的变体。
- 新增响应类型时,仅需定义对应的结构体,再往
ResponseFromNetwork中添加新变体即可,无需修改解析逻辑,维护成本极低。
内容的提问来源于stack exchange,提问作者kek_mek
相关产品推荐
相关产品推荐

