我有一堆来自DynamoDB表的实体。每个实体都有一个type
字段,标识它是什么类型的实体。类型字段是一个单项列表,其中包含一个带有类型名称的字符串。这是一个奇怪的格式,但这是我必须处理的。
我使用Serde成功地实现了一个自定义的反序列化器,将该类型转换为枚举。我目前的方法包括首先反序列化为一个带有type字段的简化结构体,然后匹配该结构体类型,并基于该类型使用适当的反序列化器。
我看到Serde支持内部标记的枚举来反序列化属于枚举中类型的其余字段,但我不知道如何调整我当前的反序列化器以选择此功能。
作为参考,这是我目前拥有的反序列化器:
use serde::{Deserialize, Deserializer, Serialize};
use types::*;
#[derive( Debug)]
enum Type {
Story,
Layer,
Unknown(String),
}
impl<'de> Deserialize<'de> for Type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = <Vec<String>>::deserialize(deserializer)?;
let k: &str = s[0].as_str();
Ok(match k {
"Story" => Type::Story,
"Layer" => Type::Layer,
v => Type::Unknown(v.to_string()),
})
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct SimpleItem {
#[serde(rename = "type")]
item_type: Type,
}
我的理想场景是这样的:
use serde::{Deserialize, Deserializer, Serialize};
use types::*;
#[derive(Deserialize, Debug)]
#[serde(tag = "type")]
enum Type {
Story { id: String, name: string, duration: u32 }
Layer { id: string, layout: string },
Unknown,
}
然后使用它直接反序列化正确的类型。
这就是我的数据可能看起来的样子:{ type: ["Story"], ...otherFields}
2条答案
按热度按时间3bygqnnd1#
Deserialize
的自定义实现通常是这种“复杂”反序列化的最佳解决方案:上述方法的一个很大的限制是它要求
"type"
字段是第一个字段。如果你想避免这种情况,最简单的方法取决于数据格式。例如,使用JSON,它可能看起来像这样:zed5wv102#
所提供的答案非常完整,而且正确。但是,永远不要低估使用默认的东西和一点前一步的方便性。在这种特殊情况下(我并不是说这可以应用于所有类似的情况),在反序列化之前对数据进行规范化可能是最简单的事情。源类型几乎就在那里了,唯一的小缺点是它被 Package 在一个无用的列表中(这只是来自不同编程语言的序列化工件)。所以,我重复一遍,在这个特定的例子中,处理这个小细节比编写一个完整的新反序列化器要容易得多,特别是因为这种格式有点复杂。
所以这就是我现在要做的,展开类型,然后让正常的serde反序列化发生。
现在,您可以正常地反序列化,而无需为内部标记的枚举定义任何自定义反序列化: