Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如何区分缺少的反序列化字段和空字段?_Rust_Serde - Fatal编程技术网

Rust 如何区分缺少的反序列化字段和空字段?

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不变 我尝试将每个字段包装在一个更高

我想使用解析一些JSON作为HTTP补丁请求的一部分。由于补丁请求不传递整个对象,只传递要更新的相关数据,因此我需要能够区分未传递的值、显式设置为
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