我怎么可能缺少一个反序列化的领域,一个是空区分?(How can I distinguish bet

2019-09-26 10:49发布

我想使用SERDE解析一些JSON作为HTTP PATCH请求的一部分。 由于PATCH请求不传递整个对象,只有相关的数据进行更新,我需要的是没有通过值之间讲的能力,这是明确设置为一个值null ,这是存在的值。

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

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

如果客户端提交JSON是这样的:

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

我想换aSome(42) bNone ,并留下c不变。

我试图在一个更公平包裹每个字段Option

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

操场

这并不加以区分bc ; 两者都None ,但我一直想bSome(None)

我不依赖于嵌套这表示Option秒; 可以区分3箱子任何解决方案将使用自定义枚举是细,诸如一个。

Answer 1:

很可能,只有这样,才能做到这一点,现在是一个自定义的反序列化功能。 幸运的是,这是不难实现,甚至使其成为任何类型的字段的工作:

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)?))
}

然后,每个场将被注释为这样的:

#[serde(deserialize_with = "deserialize_optional_field")]
a: Option<Option<i32>>,

您还需要与注释的结构#[serde(default)] ,使空字段将反序列化的“展开” None 。 诀窍是环绕现值Some

序列化依赖于另一招:跳过序列化时,该字段为None

#[serde(deserialize_with = "deserialize_optional_field")]
#[serde(skip_serializing_if = "Option::is_none")]
a: Option<Option<i32>>,

游乐场与完整的例子。 输出:

Original JSON: {"a": 42, "b": null}
> Resource { a: Some(Some(42)), b: Some(None), c: None }
< {"a":42,"b":null}


Answer 2:

建立客E_net4的回答 ,您还可以创建三个可能性的枚举:

#[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)] (或者将它应用到整个结构)。 理想的情况下,实施DeserializePatch会处理完全,但我还没有想出如何做到这一点呢。



文章来源: How can I distinguish between a deserialized field that is missing and one that is null?
标签: rust serde