如何判断Serde反序列化时未传入带默认值的字段?
解决方案
要区分timeout字段是未传入还是传入了与默认值相同的值,可以通过以下两种常用方法实现:
方法一:使用Option<T>类型直接追踪
将Request结构体中的timeout字段改为Option<Timeout>类型,反序列化时:
- 若JSON中不存在该字段,字段值为
None - 若存在该字段,字段值为
Some(Timeout)
之后你可以在业务逻辑中自行处理默认值,并通过Option的状态判断字段是否被传入:
use serde::Deserialize; #[derive(Deserialize, Debug)] struct Request { timeout: Option<Timeout>, } /// Timeout in seconds. #[derive(Deserialize, Debug)] struct Timeout(u32); fn main() { let json = r#"{}"#; let request: Request = serde_json::from_str(json).unwrap(); // 处理默认值并判断字段是否传入 let timeout = request.timeout.unwrap_or_else(|| Timeout(30)); match request.timeout { None => println!("timeout字段未传入,使用默认值"), Some(_) => println!("timeout字段已传入"), } println!("{:?}", timeout); }
方法二:自定义类型追踪显式传入/默认状态
如果希望保留#[serde(default)]的写法,同时追踪状态,可以自定义一个枚举类型,通过实现Deserialize trait来区分显式传入和默认值的场景:
use serde::{Deserialize, Deserializer}; #[derive(Debug)] enum MaybeDefault<T> { // 显式传入的值 Explicit(T), // 使用默认值(字段未传入) Default, } // 为MaybeDefault实现Default,对应字段未传入的情况 impl<T: Default> Default for MaybeDefault<T> { fn default() -> Self { MaybeDefault::Default } } // 为MaybeDefault实现Deserialize,仅当字段存在时解析为Explicit impl<'de, T: Deserialize<'de>> Deserialize<'de> for MaybeDefault<T> { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { T::deserialize(deserializer).map(MaybeDefault::Explicit) } } #[derive(Deserialize, Debug)] struct Request { #[serde(default)] timeout: MaybeDefault<Timeout>, } /// Timeout in seconds. #[derive(Deserialize, Debug)] struct Timeout(u32); impl Default for Timeout { fn default() -> Self { Timeout(30) } } fn main() { let json = r#"{}"#; let request: Request = serde_json::from_str(json).unwrap(); // 根据状态处理逻辑 match request.timeout { MaybeDefault::Default => { println!("timeout字段未传入,使用默认值"); println!("{:?}", Timeout::default()); } MaybeDefault::Explicit(val) => { println!("timeout字段已传入"); println!("{:?}", val); } } }
这两种方法都能让你明确知晓timeout字段是否被传入,而不是单纯依赖默认值的结果。
内容的提问来源于stack exchange,提问作者firefantasy
相关产品推荐
相关产品推荐

