我想使用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
不变。
我尝试将每个字段 Package 在Option
的另一个级别中:
#[derive(Debug, Deserialize)]
struct ResourcePatch {
a: Option<Option<i32>>,
b: Option<Option<i32>>,
c: Option<Option<i32>>,
}
playground
这并不区分b
和c
;两者都是None
,但我希望b
是Some(None)
。
我并不局限于这种嵌套Option
的表示;任何能够区分这3种情况的解决方案都是可以的,例如使用自定义枚举的解决方案。
4条答案
按热度按时间mzillmmw1#
在E_net4's answer的基础上,您还可以为以下三种可能性创建一个枚举:
然后,这可以用作:
不幸的是,您仍然必须使用
#[serde(default)]
注解每个字段(或将其应用于整个结构体)。理想情况下,Deserialize
forPatch
的实现可以完全处理这个问题,但我还没有弄清楚如何做到这一点。x6yk4ghg2#
很有可能,现在实现这一点的唯一方法是使用自定义的反序列化函数。幸运的是,它并不难实现,甚至可以使其适用于任何类型的领域:
然后,每个字段将被注解为:
您还需要使用
#[serde(default)]
注解结构体,以便将空字段反序列化为 “unwrapped”None
。技巧是将当前值 Package 在Some
周围。序列化依赖于另一个技巧:当字段为
None
时跳过序列化:Playground的完整示例。输出:
kiz8lqtg3#
在Shepmaster's answer上构建并添加序列化。
然后你可以这样使用它:
我希望Serde有一个内置的方法来处理JSON的
null
和absent
状态。更新2021-03-12-更新为
Maybe::Absent
,因为它更符合JSON和SQL DSL习惯。这种方法的问题是我们可以表示:
type | null
与默认Option<type>
type | null | absent
与Maybe<type>
但我们无法表达
type | absent
解决方案是将
Maybe
重构为只有::Present(value)
和::Absent
,并支持type | null | absent
的Maybe<Option<type>>
。这将给予我们全面的覆盖。type | null
与默认Option<type>
type | absent
与Maybe<type>
type | absent | null
与Maybe<Option<type>>
我试图在不添加
#[serde(deserialize_with = "deserialize_maybe_field")]
的情况下实现这一点,但不确定是否可能。我可能错过了一些明显的东西。eufgjt7s4#
您现在可以从serde_with crate中使用double_option,它完全可以满足您的需要。