如何用serde_json扁平化处理联合类型对象数组?
优化Serde反序列化:将Filter数组转换为扁平结构体
需求说明
需要将如下JSON输入:
{ "filters": [ { "filterType": "MIN_FILTER", "min": 2 }, { "filterType": "MAX_FILTER", "max": 10 }, { "filterType": "PRIORITY_FILTER", "priority": "High" } ] }
反序列化为对应如下结构的Rust对象:
{ "filters": { "min": 2, "max": 10, "priority": "High" } }
现有实现的不足
你当前用包含所有可选字段的GenericFilter结构体统一处理不同类型Filter的实现,存在几个明显问题:
- 类型不安全:每个Filter变体本应只包含专属字段,却被迫携带无关的
Option字段 - 错误处理粗糙:直接用
unwrap()会在缺失字段或数据错误时触发panic,无法返回优雅的反序列化错误 - 代码冗余:遍历数组时需要手动匹配类型并提取字段,重复逻辑多
更优方案1:用枚举实现类型安全的Filter处理
通过定义枚举对应不同Filter类型,每个枚举变体仅包含自身所需字段,再遍历枚举数组合并出最终的Filters结构体:
extern crate serde; extern crate serde_json; use serde::{Deserialize, Deserializer, Error}; #[derive(Deserialize, Debug)] pub struct Object { filters: Filters, } #[derive(Debug)] pub struct Filters { min: u32, max: u32, priority: String, } #[derive(Deserialize, Debug)] #[serde(tag = "filterType")] enum Filter { #[serde(rename = "MIN_FILTER")] MinFilter { min: u32 }, #[serde(rename = "MAX_FILTER")] MaxFilter { max: u32 }, #[serde(rename = "PRIORITY_FILTER")] PriorityFilter { priority: String }, } impl<'de> Deserialize<'de> for Filters { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let filters: Vec<Filter> = Vec::deserialize(deserializer)?; let mut min: Option<u32> = None; let mut max: Option<u32> = None; let mut priority: Option<String> = None; for filter in filters { match filter { Filter::MinFilter { min: val } => { if min.is_some() { return Err(D::Error::duplicate_field("min")); } min = Some(val); } Filter::MaxFilter { max: val } => { if max.is_some() { return Err(D::Error::duplicate_field("max")); } max = Some(val); } Filter::PriorityFilter { priority: val } => { if priority.is_some() { return Err(D::Error::duplicate_field("priority")); } priority = Some(val); } } } Ok(Filters { min: min.ok_or_else(|| D::Error::missing_field("min"))?, max: max.ok_or_else(|| D::Error::missing_field("max"))?, priority: priority.ok_or_else(|| D::Error::missing_field("priority"))?, }) } } fn main() { let json = r#" { "filters": [ { "filterType": "MIN_FILTER", "min": 2 }, { "filterType": "MAX_FILTER", "max": 10 }, { "filterType": "PRIORITY_FILTER", "priority": "High" } ] } "#; println!( "Deserialized = {:#?}", serde_json::from_str::<Object>(&json) ); }
方案优势
- 类型安全:每个Filter变体仅包含自身需要的字段,避免无关字段冗余
- 健壮错误处理:通过
ok_or_else返回标准Serde错误,替代unwrap()的panic - 扩展性强:新增Filter类型时只需添加对应枚举变体,无需修改通用结构体
更优方案2:直接使用Serde Visitor(极致性能)
如果追求更高性能,避免中间Vec<Filter>的分配,可以直接实现Visitor trait,遍历JSON数组中的每个对象并提取字段:
extern crate serde; extern crate serde_json; use serde::{de::Visitor, Deserialize, Deserializer, Error}; use std::fmt; #[derive(Deserialize, Debug)] pub struct Object { filters: Filters, } #[derive(Debug)] pub struct Filters { min: u32, max: u32, priority: String, } impl<'de> Deserialize<'de> for Filters { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { struct FiltersVisitor; impl<'de> Visitor<'de> for FiltersVisitor { type Value = Filters; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("an array of filter objects") } fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: serde::de::SeqAccess<'de>, { let mut min: Option<u32> = None; let mut max: Option<u32> = None; let mut priority: Option<String> = None; while let Some(filter_obj) = seq.next_element::<serde_json::Value>()? { let filter_type = filter_obj.get("filterType") .and_then(|v| v.as_str()) .ok_or_else(|| A::Error::missing_field("filterType"))?; match filter_type { "MIN_FILTER" => { if min.is_some() { return Err(A::Error::duplicate_field("min")); } min = filter_obj.get("min") .and_then(|v| v.as_u64()) .map(|x| x as u32) .ok_or_else(|| A::Error::missing_field("min")); } "MAX_FILTER" => { if max.is_some() { return Err(A::Error::duplicate_field("max")); } max = filter_obj.get("max") .and_then(|v| v.as_u64()) .map(|x| x as u32) .ok_or_else(|| A::Error::missing_field("max")); } "PRIORITY_FILTER" => { if priority.is_some() { return Err(A::Error::duplicate_field("priority")); } priority = filter_obj.get("priority") .and_then(|v| v.as_str()) .map(|s| s.to_string()) .ok_or_else(|| A::Error::missing_field("priority")); } _ => return Err(A::Error::unknown_variant(filter_type, &["MIN_FILTER", "MAX_FILTER", "PRIORITY_FILTER"])), }?; } Ok(Filters { min: min.ok_or_else(|| A::Error::missing_field("min"))?, max: max.ok_or_else(|| A::Error::missing_field("max"))?, priority: priority.ok_or_else(|| A::Error::missing_field("priority"))?, }) } } deserializer.deserialize_seq(FiltersVisitor) } } fn main() { let json = r#" { "filters": [ { "filterType": "MIN_FILTER", "min": 2 }, { "filterType": "MAX_FILTER", "max": 10 }, { "filterType": "PRIORITY_FILTER", "priority": "High" } ] } "#; println!( "Deserialized = {:#?}", serde_json::from_str::<Object>(&json) ); }
方案优势
- 极致性能:直接操作JSON值,避免中间枚举结构体的分配和序列化开销
- 精细控制:可直接处理JSON原始结构,适合对性能敏感的场景
- 完整错误处理:对缺失字段、重复字段、未知类型都能返回精准错误信息
内容的提问来源于stack exchange,提问作者chrigu
相关产品推荐
相关产品推荐

