我想使用SERDE解析一些JSON作为HTTP PATCH请求的一部分。 由于PATCH请求不传递整个对象,只有相关的数据进行更新,我需要的是没有通过值之间讲的能力,这是明确设置为一个值null
,这是存在的值。
我有多个可空字段的值对象:
struct Resource {
a: Option<i32>,
b: Option<i32>,
c: Option<i32>,
}
如果客户端提交JSON是这样的:
{"a": 42, "b": null}
我想换a
到Some(42)
b
到None
,并留下c
不变。
我试图在一个更公平包裹每个字段Option
:
#[derive(Debug, Deserialize)]
struct ResourcePatch {
a: Option<Option<i32>>,
b: Option<Option<i32>>,
c: Option<Option<i32>>,
}
操场
这并不加以区分b
和c
; 两者都None
,但我一直想b
是Some(None)
。
我不依赖于嵌套这表示Option
秒; 可以区分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)?))
}
然后,每个场将被注释为这样的:
#[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}
建立客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)]
(或者将它应用到整个结构)。 理想的情况下,实施Deserialize
的Patch
会处理完全,但我还没有想出如何做到这一点呢。
文章来源: How can I distinguish between a deserialized field that is missing and one that is null?