【问题标题】:Is there a way to allow an unknown enum tag when deserializing with Serde? [duplicate]使用 Serde 反序列化时,有没有办法允许未知的枚举标签? [复制]
【发布时间】:2023-04-02 00:26:01
【问题描述】:

我正在反序列化一个标记的枚举:

#[derive(Deserialize)]
enum Foo {
    A(A),
    B(B),
    C(C),
}

如果 Serde 遇到不是 ABC 的标签,则会抛出错误。有没有办法为未知标签添加一个包罗万象的变体?如果它只记录标签我会很高兴:

#[derive(Deserialize)]
enum Foo {
    A(A),
    B(B),
    C(C),
    #[serde(unknown_tag)]
    Unknown(String),
}

【问题讨论】:

  • #[serde(other)],但不会记录标签。
  • 啊,是的,不知道我是怎么错过的,谢谢!

标签: enums rust serde


【解决方案1】:

您可以为此使用untagged enum。细节取决于你想要做什么。想法是将Foo 包装成MaybeFoo,其中MaybeFoo 有一个“通用”类型可以反序列化为第二选择。

在下面的示例中,我们使用serde_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)
}

MaybeFoo 是一个“未标记”枚举,Serde 将尝试将 MaybeFoo 反序列化为 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);
}

您可以使用 serde_json 的 API 来检查未知变体 - 如果它看起来像一张地图 - 提取标签。如果这是您唯一的兴趣,MaybeFoo 的第二个变体也可以是HashMap&lt;String, serde::de::IgnoredAny&gt;,它将反序列化任何映射,将标签记录为String 并丢弃该值。但是,这假定未知值是标记值。

【讨论】:

  • 谢谢!如果我不使用 JSON 怎么办?有某种serde::Value 类型吗?我好像没找到。
  • 这取决于底层格式,有人需要对“其他”情况进行反序列化,并且没有“通用”反序列化器之类的东西。如果底层格式是基于字符串的,HashMap&lt;String, String&gt;(或者,如上所述,HashMap&lt;String, serde::de::IgnoredAny&gt; 可能会起作用。
猜你喜欢
  • 1970-01-01
  • 2022-09-24
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
相关资源
最近更新 更多