You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 06:06:00