[英]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.