使用Serde反序列化时,如何保留对应序列化数据的副本?
解决Rust Serde反序列化时保留嵌套结构体原始JSON的问题
实现思路
要实现反序列化时同时保留嵌套结构体的原始JSON字符串,需要借助Serde的自定义反序列化逻辑,结合serde_json::RawValue来捕获原始JSON片段:
- 为
InnerStruct实现自定义的Deserializetrait,在反序列化过程中先获取对应的原始JSON字符串; - 从原始JSON片段中解析出
inner_value等业务字段; - 构造最终的
InnerStruct实例,同时存入原始JSON字符串和解析后的字段值。
完整代码实现
首先确保Cargo.toml中包含必要依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
然后编写Rust代码:
use serde::de::{self, Deserialize, Deserializer}; use serde_json::value::RawValue; #[derive(Deserialize)] struct LargerStruct { value: i32, inner: InnerStruct, } struct InnerStruct { this_json: String, inner_value: i32, } // 辅助结构体,用于解析InnerStruct的业务字段 #[derive(Deserialize)] struct InnerStructHelper { inner_value: i32, } // 为InnerStruct实现自定义反序列化逻辑 impl<'de> Deserialize<'de> for InnerStruct { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { // 用RawValue捕获原始JSON片段,保留原始格式和空格 let raw_json = RawValue::deserialize(deserializer)?; let this_json = raw_json.get().to_string(); // 从原始JSON片段解析出业务字段 let helper = InnerStructHelper::deserialize(&*raw_json) .map_err(de::Error::custom)?; Ok(InnerStruct { this_json, inner_value: helper.inner_value, }) } } fn main() { let json = r#" { "value": 42, "inner": { "inner_value": 100 } } "#; // 反序列化LargerStruct,InnerStruct会自动使用自定义逻辑 let val: LargerStruct = serde_json::from_str(json).unwrap(); assert_eq!(&val.inner.this_json, r#"{ "inner_value": 100 }"#); }
关键细节说明
- RawValue的作用:
serde_json::RawValue可以直接获取反序列化时的原始JSON字节对应的字符串,完全保留输入的格式(包括空格、换行),避免了重新序列化导致的格式变化。 - 辅助结构体的意义:
InnerStructHelper简化了业务字段的解析,利用Serde自动派生的Deserialize能力,无需手动从JSON Value中提取字段,减少冗余代码。 - 自定义反序列化的范围:仅需要为需要保留原始JSON的
InnerStruct实现自定义逻辑,外层的LargerStruct可以继续使用自动派生的Deserialize,不影响其他字段的解析效率。
内容的提问来源于stack exchange,提问作者cry0genic
相关产品推荐
相关产品推荐

