你可以使用
未标记的枚举完成这个任务。具体细节取决于你想要做什么。思路是将
Foo
包装成
MaybeFoo
,其中
MaybeFoo
有一个“通用”的类型作为第二选择进行反序列化。
在下面的示例中,我们使用
serde_json::Value
作为虚拟类型,因为它的
Deserialize
实现是通用的,可以反序列化任何有效的JSON。如果你的源格式不同,你可能需要一个不同的反序列化器或者自己实现
Deserialize
。
#[derive(serde::Deserialize, serde::Serialize, PartialEq, Debug)]
enum Foo {
A(u64),
B(f32),
C(String),
}
#[derive(serde::Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum MaybeFoo {
Foo(Foo),
Other(serde_json::Value)
}
< p >
MaybeFoo
是一个“无标签”的枚举类型,Serde 会尝试将其反序列化为
Foo
,如果失败则尝试将其反序列化为
serde_json::Value
,后者始终会成功(如果来源于 JSON)。< /p >
fn main() {
let foo = Foo::B(0.0);
let foo_json = serde_json::to_string(&foo).unwrap();
println!("{}", &foo_json);
let foo_json = "{\"B\":0.0}";
assert!(serde_json::from_str::<Foo>(&foo_json).unwrap() == foo);
assert!(serde_json::from_str::<MaybeFoo>(&foo_json).unwrap() == MaybeFoo::Foo(foo));
let foo_json = "{\"Unknown\":0.0}";
let foo = serde_json::from_str::<MaybeFoo>(&foo_json).unwrap();
println!("{:?}", &foo);
}
你可以使用serde_json的API来检查未知的变体,如果它看起来像一个映射,那么可以提取标签。如果这是你唯一的兴趣,第二个
MaybeFoo
的变体也可以是
HashMap<String,serde :: de :: IgnoredAny>
,它将反序列化任何映射,将标记记录为
String
并丢弃值。但是,这假定未知值是带标签的值。
#[serde(other)]
,但它不会记录标签。 - Sven Marnach