如何将JSON键提取为Rust结构体的字段值?
解决方案
方法一:使用 HashMap 转换(简单直观)
这种方法无需自定义反序列化逻辑,先将 JSON 反序列化为 HashMap,再转换为目标结构体列表:
- 定义不含
name字段的辅助结构体,匹配 JSON 中的人员详情:
use serde::Deserialize; use std::collections::HashMap; #[derive(Debug, Deserialize)] struct PersonDetails { pub age: u32, pub gender: Option<String>, }
- 反序列化 JSON 为 HashMap,再转换为
Vec<Person>:
#[derive(Debug)] pub struct Person { pub name: String, pub age: u32, pub gender: Option<String>, } // 示例 JSON 字符串 let json = r#"{ "Bob": { "age": 41, "gender": "M" }, "Alice": { "age": 34, "gender": "F" } }"#; // 反序列化为 HashMap let person_map: HashMap<String, PersonDetails> = serde_json::from_str(json)?; // 转换为 Vec<Person> let people: Vec<Person> = person_map .into_iter() .map(|(name, details)| Person { name, age: details.age, gender: details.gender, }) .collect();
此方法代码简洁易维护,缺点是需要额外的 HashMap 存储和转换步骤,大数据量场景下效率稍低。
方法二:自定义反序列化访问器(高效单步)
若追求更高效率,可实现自定义 Serde 访问器,直接将 JSON 映射转换为 Vec<Person>,无需中间结构:
- 修改
Person结构体,标记name字段跳过反序列化(它来自 JSON 的键):
use serde::{Deserialize, Deserializer}; use serde::de::{Visitor, MapAccess}; use std::fmt; #[derive(Debug, Deserialize)] pub struct Person { #[serde(skip_deserializing)] pub name: String, pub age: u32, pub gender: Option<String>, }
- 实现自定义访问器和反序列化逻辑:
struct PersonMapVisitor; impl<'de> Visitor<'de> for PersonMapVisitor { type Value = Vec<Person>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("一个以姓名为键、人员详情为值的 JSON 对象") } fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error> where M: MapAccess<'de>, { let mut people = Vec::new(); while let Some((name, mut person)) = map.next_entry::<String, Person>()? { person.name = name; people.push(person); } Ok(people) } } // 辅助函数:使用自定义访问器反序列化 fn deserialize_people<'de, D>(deserializer: D) -> Result<Vec<Person>, D::Error> where D: Deserializer<'de>, { deserializer.deserialize_map(PersonMapVisitor) }
- 使用
DeserializeSeed直接反序列化为Vec<Person>(无需包装结构体):
struct PeopleSeed; impl<'de> serde::de::DeserializeSeed<'de> for PeopleSeed { type Value = Vec<Person>; fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where D: Deserializer<'de>, { deserialize_people(deserializer) } } // 反序列化示例 let deserializer = serde_json::Deserializer::from_str(json); let people = PeopleSeed.deserialize(deserializer)?;
此方法单步完成反序列化,效率更高;缺点是需要编写更多自定义 Serde 代码,复杂度稍高。
内容的提问来源于stack exchange,提问作者romatthe
相关产品推荐
相关产品推荐

