我正在反序列化一个标记的枚举:
#[derive(Deserialize)]
enum Foo {
A(A),
B(B),
C(C),
}
Run Code Online (Sandbox Code Playgroud)
如果 Serde 遇到一个不是A,B或的标签C,那么它会抛出一个错误。有什么方法可以为未知标签添加一个包罗万象的变体?如果它只记录标签,我会很高兴:
#[derive(Deserialize)]
enum Foo {
A(A),
B(B),
C(C),
}
Run Code Online (Sandbox Code Playgroud)
您可以为此使用未标记的枚举。详细信息取决于您具体想要做什么。这个想法是包装Foo成一个MaybeFoo,其中MaybeFoo有一个“通用”类型可以反序列化为第二选择。
在下面的示例中,我们使用 aserde_json::Value作为虚拟类型,因为它的实现Deserialize是通用的,可以反序列化任何有效的 JSON。如果您的源格式不同,您可能需要不同的解串器或Deserialize自己实现。
#[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)
}
Run Code Online (Sandbox Code Playgroud)
这MaybeFoo是一个“未标记”的枚举,Serde 将尝试反序列MaybeFoo化为 a Foo- 如果失败 - 因为serde_json::Value它总是会成功(如果源自 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);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用 serde_json 的 API 来检查未知变体 - 如果它看起来像地图 - 提取标签。如果这是您唯一的兴趣, 的第二个变体MaybeFoo也可以是 a HashMap<String, serde::de::IgnoredAny>,它将反序列化任何映射,将标签记录为 aString并丢弃该值。然而,这假定未知值是标记值。