Rust中使用flatten时如何实现JSON键转换反序列化?
解决Rust中serde flatten时字符串键转u32 HashMap的问题
核心原因
serde在处理#[serde(flatten)]嵌套结构体时,不会自动沿用直接结构体场景下的字符串键转数字键逻辑,需要显式指定转换规则。
方法1:使用serde_with工具库(推荐)
借助serde_with提供的现成转换函数,无需手动编写复杂逻辑:
- 添加依赖到
Cargo.toml:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_with = "3.0"
- 修改结构体定义,给HashMap字段加上
deserialize_with属性:
use serde::Deserialize; use std::collections::HashMap; // 导入serde_with提供的字符串转u32键的反序列化函数 use serde_with::rust::string_number::deserialize as string_to_u32; #[derive(Deserialize, Debug)] struct InfoContainer { #[serde(deserialize_with = "string_to_u32")] data: HashMap<u32, String>, } #[derive(Deserialize, Debug)] struct ContainedInfo { other_field: String, #[serde(flatten)] container: InfoContainer, }
这样反序列化时,JSON中的字符串键会被自动转换为u32类型,同时保留flatten特性。
方法2:手动编写简单转换函数(无额外依赖)
如果不想引入新依赖,可以自己写一个轻量的转换函数,替代serde_with的工具:
use serde::Deserialize; use std::collections::HashMap; use serde::de::Error; use std::str::FromStr; // 自定义转换函数:将字符串键的HashMap转为u32键的HashMap fn deserialize_string_to_u32_map<'de, D>(deserializer: D) -> Result<HashMap<u32, String>, D::Error> where D: serde::Deserializer<'de>, { // 先反序列化为字符串键的HashMap let string_map: HashMap<String, String> = HashMap::deserialize(deserializer)?; // 遍历转换键类型,处理可能的转换错误 string_map.into_iter() .map(|(key, value)| { u32::from_str(&key) .map_err(|err| D::Error::custom(format!("Invalid u32 key: {}", err))) .map(|num_key| (num_key, value)) }) .collect() } #[derive(Deserialize, Debug)] struct InfoContainer { #[serde(deserialize_with = "deserialize_string_to_u32_map")] data: HashMap<u32, String>, } #[derive(Deserialize, Debug)] struct ContainedInfo { other_field: String, #[serde(flatten)] container: InfoContainer, }
验证示例
用以下JSON测试:
{ "other_field": "test", "data": { "1": "value1", "2": "value2" } }
反序列化代码:
fn main() -> Result<(), serde_json::Error> { let json_str = r#"{"other_field": "test", "data": {"1": "value1", "2": "value2"}}"#; let info: ContainedInfo = serde_json::from_str(json_str)?; println!("{:?}", info); Ok(()) }
运行后会正常输出转换后的结构体,且data字段的HashMap键为u32类型。
内容的提问来源于stack exchange,提问作者executor21
相关产品推荐
相关产品推荐

