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

2024-04-25

我想用Serde https://serde.rs/将一些 JSON 解析为 HTTP PATCH 请求的一部分。由于 PATCH 请求不传递整个对象,仅传递要更新的相关数据,因此我需要能够区分未传递的值和显式设置为的值null,以及存在的值。

我有一个具有多个可为空字段的值对象:

struct Resource {
    a: Option<i32>,
    b: Option<i32>,
    c: Option<i32>,
}

如果客户端像这样提交 JSON:

{"a": 42, "b": null}

我想改变a to Some(42), b to None, 然后离开c不变。

我尝试将每个字段包装为多一层Option:

#[derive(Debug, Deserialize)]
struct ResourcePatch {
    a: Option<Option<i32>>,
    b: Option<Option<i32>>,
    c: Option<Option<i32>>,
}

这并不区分b and c;两者都是None但我想要b to be Some(None).

我与嵌套的这种表示无关Options;任何能够区分这 3 种情况的解决方案都可以,例如使用自定义枚举的解决方案。


建立在E_net4的回答 https://stackoverflow.com/a/44331646/155423,您还可以为三种可能性创建一个枚举:

#[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)
    }
}

然后可以将其用作:

#[derive(Debug, Deserialize)]
struct ResourcePatch {
    #[serde(default)]
    a: Patch<i32>,
}

不幸的是,您仍然必须用注释来注释每个字段#[serde(default)](或将其应用于整个结构)。理想情况下,实施Deserialize for Patch可以完全处理这个问题,但我还没有弄清楚如何做到这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何区分缺少的反序列化字段和空字段? 的相关文章

随机推荐