一种方法是自己进行地图的反序列化:
use std::fmt;
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
use serde_derive::Deserialize;
struct ItemMapVisitor {}
impl ItemMapVisitor {
fn new() -> Self {
Self {}
}
}
#[derive(Debug, Deserialize)]
struct SomeField {
some_field: u32,
}
#[derive(Debug)]
struct Item {
name: String,
some_field: u32,
}
#[derive(Debug)]
struct VecItem(Vec<Item>);
impl Item {
fn new(name: String, some_field: u32) -> Self {
Self { name, some_field }
}
}
impl<'de> Visitor<'de> for ItemMapVisitor {
type Value = VecItem;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("name: somefield:")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut items = Vec::with_capacity(access.size_hint().unwrap_or(0));
while let Some((key, value)) = access.next_entry::<String, SomeField>()? {
items.push(Item::new(key, value.some_field));
}
Ok(VecItem(items))
}
}
impl<'de> Deserialize<'de> for VecItem {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(ItemMapVisitor::new())
}
}
fn main() {
let contents = r#"
name_a:
some_field: 0
name_b:
some_field: 1
name_c:
some_field: 2
"#;
let items: VecItem = serde_yaml::from_str(&contents).unwrap();
println!("{:#?}", items);
}
输出:
VecItem(
[
Item {
name: "name_a",
some_field: 0
},
Item {
name: "name_b",
some_field: 1
},
Item {
name: "name_c",
some_field: 2
}
]
)
如果您不想使用
Somefield
结构体,也可以使用以下方法:
#[derive(Debug, Deserialize)]
struct Item {
#[serde(skip)]
name: String,
some_field: u32,
}
while let Some((key, value)) = access.next_entry::<String, Item>()? {
items.push(Item::new(key, value.some_field));
}
但是这可能会添加一些无用的复制内容。
name
存在重复值时,应该发生什么?它只会生成无效数据吗? - ShepmasterMap<String, PartialItem>
,然后将其转换为Vec<Item>
;我猜你想避免创建瞬态的Map
? - ShepmasterPartialItem
结构体。使用Option<String>
作为名称是可能的,尽管我认为这不是最佳选择。如果没有更好的选择,也许暂时的Map
是我必须采取的方法。 - Tim Visée