我想用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)
.
我与嵌套的这种表示无关Option
s;任何能够区分这 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(使用前将#替换为@)