Rust中如何正确处理null、空JSON反序列化,统一转为None值
Rust JSON反序列化同时适配null和空对象为None的解决方案
依赖配置
首先确保Cargo.toml中引入了对应依赖:
[package] name = "serde-demo" version = "0.1.0" edition = "2021" [dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
方案1:单字段自定义反序列化(按需使用)
通过serde的deserialize_with属性为单个字段指定自定义反序列化逻辑,直接复用即可覆盖null和空对象两种场景:
use serde::{Deserialize, Deserializer}; use serde_json::Value; /// 自定义反序列化逻辑:null或空对象都反序列化为None fn deserialize_empty_as_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error> where T: Deserialize<'de>, D: Deserializer<'de>, { let val = Option::<Value>::deserialize(deserializer)?; match val { // 匹配null值 None => Ok(None), // 匹配空对象 Some(Value::Object(obj)) if obj.is_empty() => Ok(None), // 非空有效值正常反序列化 Some(v) => T::deserialize(v).map(Some).map_err(serde::de::Error::custom), } } // 业务结构体示例 #[derive(Debug, Deserialize, PartialEq)] struct InnerData { valid_json: i32, } #[derive(Debug, Deserialize, PartialEq)] struct BusinessData { // 为指定字段绑定自定义反序列化逻辑,加default可兼容字段不存在的场景 #[serde(deserialize_with = "deserialize_empty_as_none", default)] test: Option<InnerData>, }
方案2:通用包装类型(全局复用)
如果多个字段都需要该逻辑,可以定义通用的包装类型,避免重复标注deserialize_with:
use serde::{Deserialize, Deserializer}; use serde_json::Value; #[derive(Debug, Clone, PartialEq, Eq)] pub struct EmptyAsNone<T>(pub Option<T>); impl<'de, T> Deserialize<'de> for EmptyAsNone<T> where T: Deserialize<'de>, { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let val = Option::<Value>::deserialize(deserializer)?; match val { None => Ok(Self(None)), Some(Value::Object(obj)) if obj.is_empty() => Ok(Self(None)), Some(v) => T::deserialize(v).map(|inner| Self(Some(inner))).map_err(serde::de::Error::custom), } } } // 用法示例 #[derive(Debug, Deserialize, PartialEq)] struct InnerData { valid_json: i32, } #[derive(Debug, Deserialize, PartialEq)] struct BusinessData { test: EmptyAsNone<InnerData>, }
测试验证
以下测试用例可覆盖三种要求的场景:
fn main() { // 场景1:字段值为null let input1 = r#"{"test": null}"#; let res1: BusinessData = serde_json::from_str(input1).unwrap(); assert!(res1.test.is_none()); // 场景2:字段值为空对象 let input2 = r#"{"test": {}}"#; let res2: BusinessData = serde_json::from_str(input2).unwrap(); assert!(res2.test.is_none()); // 场景3:字段值为有效非空对象 let input3 = r#"{"test": {"valid_json": 42}}"#; let res3: BusinessData = serde_json::from_str(input3).unwrap(); assert_eq!(res3.test.unwrap().valid_json, 42); }
内容的提问来源于stack exchange,提问作者Barry King
相关产品推荐
相关产品推荐

