在Shepmaster的回答基础上,加入序列化。
use serde::ser::Error;
use serde::{Deserialize, Deserializer};
use serde::{Serialize, Serializer};
#[derive(Debug)]
pub enum Maybe<T> {
Absent,
Null,
Value(T),
}
#[allow(dead_code)]
impl<T> Maybe<T> {
pub fn is_absent(&self) -> bool {
match &self {
Maybe::Absent => true,
_ => false,
}
}
}
impl<T> Default for Maybe<T> {
fn default() -> Self {
Maybe::Absent
}
}
impl<T> From<Option<T>> for Maybe<T> {
fn from(opt: Option<T>) -> Maybe<T> {
match opt {
Some(v) => Maybe::Value(v),
None => Maybe::Null,
}
}
}
impl<'de, T> Deserialize<'de> for Maybe<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let d = Option::deserialize(deserializer).map(Into::into);
d
}
}
impl<T: Serialize> Serialize for Maybe<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Maybe::Null => serializer.serialize_none(),
Maybe::Value(v) => v.serialize(serializer),
Maybe::Absent => Err(Error::custom(
r#"Maybe fields need to be annotated with:
#[serde(default, skip_serializing_if = "Maybe::is_Absent")]"#,
)),
}
}
}
接下来,您可以按照以下方式使用它:
#[derive(Serialize, Deserialize, Debug)]
struct Rect {
#[serde(default, skip_serializing_if = "Maybe::is_absent")]
stroke: Maybe<i32>,
w: i32,
#[serde(default, skip_serializing_if = "Maybe::is_absent")]
h: Maybe<i32>,
}
let json = r#"
{
"stroke": null,
"w": 1
}"#;
let deserialized: Rect = serde_json::from_str(json).unwrap();
println!("deserialized = {:?}", deserialized);
let serialized = serde_json::to_string(&deserialized).unwrap();
println!("serialized back = {}", serialized);
我希望Serde有一个内置的方式来处理JSON的
null
和
absent
状态。
更新于2021-03-12 - 更新为
Maybe::Absent
,因为它更符合JSON和SQL DSL的习惯用法。
这种方法的问题在于我们可以使用以下方式表示:
- 用默认值
Option<type>
表示
type | null
- 使用
Maybe<type>
表示
type | null | absent
但是我们无法表示
type | absent
。
解决方案是将
Maybe
重构为只具有
::Present(value)
和
::Absent
,并支持
Maybe<Option<type>>
用于
type | null | absent
。这样就可以实现全覆盖。
- 用默认值
Option<type>
表示
type | null
- 使用
Maybe<type>
表示
type | absent
- 使用
Maybe<Option<type>>
表示
type | absent | null
我正在尝试在不添加
#[serde(deserialize_with = "deserialize_maybe_field")]
的情况下实现此目标,但不确定是否可能。我可能忽略了一些显而易见的东西。
Patch
的Deserialize
实现将完全处理这一点。到目前为止,我的假设是这是不可能的。从你尝试反序列化Patch
开始,你期望该值以其序列化形式存在。相反,Patch::Missing
通过在容器中的“不存在”而存在(你不能将Patch::Missing
单独序列化为 JSON)。据我所知,Serialize
无法选择不被序列化,也无法告诉容器跳过该过程的那一部分。 - E net4Deserialize
无法告诉Deserializer
反序列化它根本找不到的值。如果我们有一个空对象{}
,那么Deserialize
的实现将对此无能为力,但是一旦反序列化器知道要填充默认值,它就可以做到。 - E net4