Rust 如何区分缺少的反序列化字段和空字段?
我想使用解析一些JSON作为HTTP补丁请求的一部分。由于补丁请求不传递整个对象,只传递要更新的相关数据,因此我需要能够区分未传递的值、显式设置为Rust 如何区分缺少的反序列化字段和空字段?,rust,serde,Rust,Serde,我想使用解析一些JSON作为HTTP补丁请求的一部分。由于补丁请求不传递整个对象,只传递要更新的相关数据,因此我需要能够区分未传递的值、显式设置为null的值和存在的值 我有一个具有多个可为空字段的值对象: struct Resource { a: Option<i32>, b: Option<i32>, c: Option<i32>, } 我想将a更改为Some(42),b更改为None,并保持c不变 我尝试将每个字段包装在一个更高
null
的值和存在的值
我有一个具有多个可为空字段的值对象:
struct Resource {
a: Option<i32>,
b: Option<i32>,
c: Option<i32>,
}
我想将a
更改为Some(42)
,b
更改为None
,并保持c
不变
我尝试将每个字段包装在一个更高级别的选项中
:
#[derive(Debug, Deserialize)]
struct ResourcePatch {
a: Option<Option<i32>>,
b: Option<Option<i32>>,
c: Option<Option<i32>>,
}
#[派生(调试、反序列化)]
结构资源补丁{
答:选择,
b:选择,
c:选项,
}
这并不区分b
和c
;两者都是None
,但我希望b
是一些(None)
我不喜欢嵌套的
选项
s的这种表示;任何能够区分这3种情况的解决方案都可以,例如使用自定义枚举的解决方案。很可能,现在实现这一点的唯一方法是使用自定义反序列化函数。幸运的是,实施起来并不难,即使是让它在任何领域都能发挥作用:
fn deserialize_optional_field<'de, T, D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
Ok(Some(Option::deserialize(deserializer)?))
}
用完整的例子。输出:
原始JSON:{“a”:42,“b”:null}
>资源{a:Some(Some(42)),b:Some(None),c:None}
<{a:42,“b:null}
很可能,目前实现这一点的唯一方法是使用自定义反序列化函数。幸运的是,实施起来并不难,即使是让它在任何领域都能发挥作用:
fn deserialize_optional_field<'de, T, D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
Ok(Some(Option::deserialize(deserializer)?))
}
用完整的例子。输出:
原始JSON:{“a”:42,“b”:null}
>资源{a:Some(Some(42)),b:Some(None),c:None}
<{a:42,“b:null}
基于,您还可以为以下三种可能性创建枚举:
#[derive(Debug)]
enum Patch<T> {
Missing,
Null,
Value(T),
}
impl<T> Default for Patch<T> {
fn default() -> Self {
Patch::Missing
}
}
impl<T> From<Option<T>> for Patch<T> {
fn from(opt: Option<T>) -> Patch<T> {
match opt {
Some(v) => Patch::Value(v),
None => Patch::Null,
}
}
}
impl<'de, T> Deserialize<'de> for Patch<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Option::deserialize(deserializer).map(Into::into)
}
}
#[派生(调试)]
枚举补丁{
丢失的
无效的
值(T),
}
补丁的impl默认值{
fn default()->Self{
修补程序::缺少
}
}
从中为修补程序执行impl{
fn from(选项:Option)->补丁{
匹配选项{
一些(v)=>Patch::Value(v),
None=>Patch::Null,
}
}
}
补丁的impl
哪里
T:反序列化,
{
选项::反序列化(反序列化器).map(到::到)
}
}
然后可将其用作:
#[derive(Debug, Deserialize)]
struct ResourcePatch {
#[serde(default)]
a: Patch<i32>,
}
#[派生(调试、反序列化)]
结构资源补丁{
#[serde(默认)]
a:补丁,
}
不幸的是,您仍然必须使用
#[serde(默认)]
注释每个字段(或将其应用于整个结构)。理想情况下,为补丁
实现反序列化
可以完全解决这个问题,但我还没有弄清楚如何做到这一点。基于,您还可以为以下三种可能性创建枚举:
#[derive(Debug)]
enum Patch<T> {
Missing,
Null,
Value(T),
}
impl<T> Default for Patch<T> {
fn default() -> Self {
Patch::Missing
}
}
impl<T> From<Option<T>> for Patch<T> {
fn from(opt: Option<T>) -> Patch<T> {
match opt {
Some(v) => Patch::Value(v),
None => Patch::Null,
}
}
}
impl<'de, T> Deserialize<'de> for Patch<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Option::deserialize(deserializer).map(Into::into)
}
}
#[派生(调试)]
枚举补丁{
丢失的
无效的
值(T),
}
补丁的impl默认值{
fn default()->Self{
修补程序::缺少
}
}
从中为修补程序执行impl{
fn from(选项:Option)->补丁{
匹配选项{
一些(v)=>Patch::Value(v),
None=>Patch::Null,
}
}
}
补丁的impl
哪里
T:反序列化,
{
选项::反序列化(反序列化器).map(到::到)
}
}
然后可将其用作:
#[derive(Debug, Deserialize)]
struct ResourcePatch {
#[serde(default)]
a: Patch<i32>,
}
#[派生(调试、反序列化)]
结构资源补丁{
#[serde(默认)]
a:补丁,
}
不幸的是,您仍然必须使用
#[serde(默认)]
注释每个字段(或将其应用于整个结构)。理想情况下,补丁
的反序列化
的实现可以完全解决这个问题,但我还没有弄清楚如何做到这一点。建立并添加序列化
使用serde::ser::Error;
使用serde::{反序列化,反序列化程序};
使用serde::{Serialize,Serializer};
//#地区------不支持JSON
//建立在…之上https://stackoverflow.com/a/44332837
///serde Valueue,可以不存在、空或Valueue(T)
#[导出(调试)]
也许吧{
缺席的
无效的
值(T),
}
#[允许(死代码)]
也许吧{
pub fn不存在(&self)->bool{
匹配与自我{
也许::缺席=>对,
_=>错误,
}
}
}
impl默认为Maybe{
fn default()->Self{
也许……缺席
}
}
也许是因为{
fn from(opt:Option)->可能{
匹配选项{
一些(v)=>可能::值(v),
None=>Maybe::Null,
}
}
}
也许吧
哪里
T:反序列化,
{
让d=Option::反序列化(反序列化器).map(Into::Into);
D
}
}
可能的impl序列化{
fn序列化(&self,序列化程序:S)->结果
哪里
S:序列化程序,
{
匹配自我{
//这将被序列化为null
可能::Null=>serializer.serialize_none(),
可能::Value(v)=>v.serialize(serializer),
//应该跳过的
可能::缺席=>错误(错误::自定义(
r#“可能字段需要注释为:
#[serde(默认值,跳过序列化(如果=“Maybe::is_缺席”)”,
)),
}
}
}
//#endregion---JSON不支持
然后你可以这样使用它:
#[派生(序列化、反序列化、调试)]
结构矩形{
#[serde(默认值,如果=“Maybe::is\u缺席”,则跳过序列化]]
中风:也许,
w:i32,
#[serde(默认值,如果=“Maybe::is\u缺席”,则跳过序列化]]
h:也许,
}
// ....
让json=r#”
{
“笔划”:空,
“w”:1
}"#;
让我们反序列化:Rect=serde_json::from_str(json).unwrap();
普林顿!(“反序列化={:?}”,反序列化);
//将输出:Rect{stroke:Null,w:1,h:缺席}
让serialized=serde_json::to_string(&反序列化);
普林顿!(“序列化后={}”,序列化);
//将输出:{“stroke”:null,“w”:1}
我希望Serde有一种处理J