【问题标题】:How do you deserialize a string with an enum where any other value deserializes into a newtype variant while preserving the string?您如何使用枚举反序列化字符串,其中任何其他值反序列化为新类型变体同时保留字符串?
【发布时间】:2023-01-12 13:13:02
【问题描述】:

我有一个类似于以下的枚举:

#[derive(Deserialize)]
enum ExampleEnum {
    #[serde(rename = "variant1-rename")]
    Variant1,
    #[serde(rename = "variant2-rename")]
    Variant2,
    Other(String),
}

它应该像这样反序列化:

Serialized Deserialized
"variant1-rename" ExampleEnum::Variant1
"variant2-rename" ExampleEnum::Variant2
"foobar" ExampleEnum::Other("foobar")

使用我当前的代码,前两个按预期工作,但最后一个没有,程序错误说它期望“variant1-rename”、“variant2-rename”或“Other”。

#[serde(other)] 属性似乎会导致所需的行为,但它只能与内部标记或相邻标记的枚举一起使用。

我正在反序列化的 (JSON) 数据有一个属性应该被反序列化到枚举中,所以它看起来像这样:

{
    "property": "variant1-rename"
}

【问题讨论】:

    标签: rust deserialization serde


    【解决方案1】:

    除了向 serde 开放功能请求外,我认为唯一的方法是手动实现Deserialize

    #[derive(Debug)]
    enum ExampleEnum {
        Variant1,
        Variant2,
        Other(String),
    }
    
    impl<'de> Deserialize<'de> for ExampleEnum {
        fn deserialize<D>(de: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            let variant = Cow::<'de, str>::deserialize(de)?;
            Ok(match variant.as_ref() {
                "variant1-rename" => ExampleEnum::Variant1,
                "variant2-rename" => ExampleEnum::Variant2,
                _other => ExampleEnum::Other(variant.into_owned()),
            })
        }
    }
    

    如果您没有重命名所有变体,您可以使用enum_derive::FromStr 使它更平滑一些。

    【讨论】:

      猜你喜欢
      • 2017-04-07
      • 1970-01-01
      • 2011-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-03
      • 1970-01-01
      • 2021-06-18
      相关资源
      最近更新 更多