Rust中使用serde无中间结构实现记录转列式反序列化的方法
实现方案
serde 完全支持跳过中间结构直接完成目标格式反序列化,通过手动实现Deserialize trait 即可满足需求,具体实现如下:
依赖配置
首先在Cargo.toml中引入必要依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
核心代码实现
use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use serde_json::Value; use std::fmt; // 目标结构体,Rust约定结构体使用大驼峰命名 #[derive(Debug, PartialEq)] struct Data { key1: Vec<i8>, key2: Vec<i8>, } impl<'de> Deserialize<'de> for Data { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { struct DataVisitor; impl<'de> Visitor<'de> for DataVisitor { type Value = Data; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("array of objects or 2D array of i8") } // 处理外层数组,两种输入的外层均为数组结构 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> where A: SeqAccess<'de>, { // 直接初始化目标字段的Vec,不需要中间存储 let mut key1 = Vec::new(); let mut key2 = Vec::new(); while let Some(element) = seq.next_element::<Value>()? { match element { // 兼容第一种输入:数组元素为JSON对象 Value::Object(mut map) => { let k1 = map .get("key1") .and_then(|v| v.as_i64()) .ok_or_else(|| serde::de::Error::custom("missing or invalid key1"))? as i8; let k2 = map .get("key2") .and_then(|v| v.as_i64()) .ok_or_else(|| serde::de::Error::custom("missing or invalid key2"))? as i8; key1.push(k1); key2.push(k2); } // 兼容第二种输入:数组元素为嵌套数组 Value::Array(mut arr) => { if arr.len() != 2 { return Err(serde::de::Error::custom( "inner array must have exactly 2 elements", )); } let k1 = arr .remove(0) .as_i64() .ok_or_else(|| serde::de::Error::custom("invalid first element"))? as i8; let k2 = arr .remove(0) .as_i64() .ok_or_else(|| serde::de::Error::custom("invalid second element"))? as i8; key1.push(k1); key2.push(k2); } _ => return Err(serde::de::Error::custom("invalid element type")), } } Ok(Data { key1, key2 }) } } deserializer.deserialize_seq(DataVisitor) } } // 测试代码 fn main() -> Result<(), Box<dyn std::error::Error>> { // 测试第一种输入:对象数组(如果你的原始输入没有外层[],手动拼接即可转为合法JSON) let obj_input = r#"[ {"key1": 40, "key2": 50}, {"key1": 41, "key2": 51} ]"#; let data1: Data = serde_json::from_str(obj_input)?; assert_eq!(data1.key1, vec![40, 41]); assert_eq!(data1.key2, vec![50, 51]); // 测试第二种输入:嵌套数组 let arr_input = r#"[[40,50],[41,51]]"#; let data2: Data = serde_json::from_str(arr_input)?; assert_eq!(data2.key1, vec![40, 41]); assert_eq!(data2.key2, vec![50, 51]); println!("两种格式反序列化均验证通过"); Ok(()) }
实现说明
- 全程没有创建中间结构体、中间
Vec<Vec<i8>>等临时对象,反序列化过程中直接将对应值写入目标结构体的Vec字段,性能开销更低 - 自动兼容两种输入格式,不需要额外的格式判断逻辑
- 可以根据业务需求扩展错误处理逻辑,处理字段缺失、类型不匹配等异常场景
- 如果第一种原始输入是无外层数组包裹的裸对象序列,只需在输入字符串首尾拼接
[和]转换为合法JSON数组后再调用反序列化方法即可
内容的提问来源于stack exchange,提问作者mbfernan
相关产品推荐
相关产品推荐

