使用 Serde 反序列化时,有没有办法允许未知的枚举标签? [英] Is there a way to allow an unknown enum tag when deserializing with Serde?
问题描述
我正在反序列化一个带标签的枚举:
I'm deserializing a tagged enum:
#[derive(Deserialize)]
enum Foo {
A(A),
B(B),
C(C),
}
如果 Serde 遇到一个不是 A
、B
或 C
的标签,那么它会抛出一个错误.有什么方法可以为未知标签添加一个包罗万象的变体?如果它只记录标签,我会很高兴:
If Serde encounters a tag that isn't A
, B
or C
, then it will throw an error. Is there any way to add a catch-all variant for unknown tags? I'd be happy if it only records the tag:
#[derive(Deserialize)]
enum Foo {
A(A),
B(B),
C(C),
#[serde(unknown_tag)]
Unknown(String),
}
推荐答案
您可以使用 untagged枚举为此.细节取决于你想要做什么.这个想法是将 Foo
包装成一个 MaybeFoo
,其中 MaybeFoo
有一个通用"反序列化的类型作为第二选择.
You can use an untagged enum for this. The details depend on what you want to do exactly. The idea is to wrap Foo
into a MaybeFoo
, where MaybeFoo
has a "universal" type to deserialize into as the second choice.
在下面的示例中,我们使用 serde_json::Value
作为虚拟类型,因为它的 Deserialize
实现是通用的,可以反序列化任何有效的 JSON.如果您的源格式不同,您可能需要不同的反序列化器或自己实现Deserialize
.
In the example below, we use a serde_json::Value
as a dummy-type, as its implementation of Deserialize
is universal as can deserialize anything that is valid JSON. If your source format is different, you may need a different deserializer or implement Deserialize
yourself.
#[derive(serde::Deserialize, serde::Serialize, PartialEq, Debug)]
enum Foo {
A(u64),
B(f32),
C(String),
}
// MaybeFoo is untagged, which also means it "looks" exactly
// like a Foo when serialized/deserialized.
#[derive(serde::Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum MaybeFoo {
Foo(Foo),
Other(serde_json::Value)
}
MaybeFoo
是一个未标记的"代码.枚举和 Serde 将尝试将 MaybeFoo
反序列化为 Foo
并且 - 如果失败 - 作为 serde_json::Value
它将总是成功(如果来源来自 JSON).
The MaybeFoo
is an "untagged" enum and Serde will try to deserialize MaybeFoo
as a Foo
and - if that fails - as serde_json::Value
which will always succeed (if sourced from JSON).
fn main() {
// Lets create a Foo and serialize it
let foo = Foo::B(0.0);
let foo_json = serde_json::to_string(&foo).unwrap();
println!("{}", &foo_json);
// Deserialize works as expected
let foo_json = "{\"B\":0.0}";
assert!(serde_json::from_str::<Foo>(&foo_json).unwrap() == foo);
// Deserializing as a `MaybeFoo` works as expected
assert!(serde_json::from_str::<MaybeFoo>(&foo_json).unwrap() == MaybeFoo::Foo(foo));
// Deserializing something else is not a `Foo`!
let foo_json = "{\"Unknown\":0.0}";
let foo = serde_json::from_str::<MaybeFoo>(&foo_json).unwrap();
// Prints "Other(Object({"Unknown": Number(0.0)}))"
println!("{:?}", &foo);
}
您可以使用 serde_json 的 API 来检查未知变体,并且 - 如果它看起来像地图 - 提取标签.如果这是您唯一的兴趣,MaybeFoo
的第二个变体也可以是 HashMap
,它将反序列化任何映射,记录标记为 String
并丢弃该值.但是,这假定未知值是标记值.
You can use serde_json's API to inspect the unknown variant and - if it looks like a map - extract the tag. If this is your only interest, the second variant of MaybeFoo
could also be a HashMap<String, serde::de::IgnoredAny>
, which will deserialize any map, record the tag as a String
and throw away the value. This presumes, however, that the unknown value is a tagged value.
这篇关于使用 Serde 反序列化时,有没有办法允许未知的枚举标签?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!