【问题标题】: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 使它更平滑一些。