簡體   English   中英

您如何使用枚舉反序列化字符串,其中任何其他值反序列化為新類型變體同時保留字符串?

[英]How do you deserialize a string with an enum where any other value deserializes into a newtype variant while preserving the string?

我有一個類似於以下的枚舉:

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

它應該像這樣反序列化:

連載 反序列化
"variant1-rename" ExampleEnum::Variant1
"variant2-rename" ExampleEnum::Variant2
"foobar" ExampleEnum::Other("foobar")

使用我當前的代碼,前兩個按預期工作,但最后一個沒有,程序錯誤說它期望“variant1-rename”、“variant2-rename”或“Other”。

#[serde(other)]屬性似乎會導致所需的行為,但它只能與內部標記或相鄰標記的枚舉一起使用。

我正在反序列化的 (JSON) 數據有一個屬性應該被反序列化到枚舉中,所以它看起來像這樣:

{
    "property": "variant1-rename"
}

除了向 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 = String::deserialize(de)?;
        Ok(match variant.as_str() {
            "variant1-rename" => ExampleEnum::Variant1,
            "variant2-rename" => ExampleEnum::Variant2,
            _other => ExampleEnum::Other(variant),
        })
    }
}

如果您沒有重命名所有變體,則可以使用enum_derive::FromStr更平滑一些。

這是我解決問題的代碼,基於Caesar 的回答serde文檔中的Manually implementing Deserialize for a struct page。

use serde::{ Deserialize, de };

impl<'de> Deserialize<'de> for ExampleEnum {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct ExampleEnumVisitor;

        impl<'de> de::Visitor<'de> for ExampleEnumVisitor {
            type Value = ExampleEnum;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("`variant1-rename`, `variant2-rename`, or some other string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                match v {
                    "variant1-rename" => Ok(ExampleEnum::Variant1),
                    "variant2-rename" => Ok(ExampleEnum::Variant2),
                    _ => Ok(ExampleEnum::Other(v.to_string())),
                }
            }
        }

        deserializer.deserialize_identifier(ExampleEnumVisitor)
    }
}

如果您希望獲得更短的解決方案,請使用Caesar 的. 閱讀他們解決方案下的評論以了解差異。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM