You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中使用flatten时如何实现JSON键转换反序列化?

解决Rust中serde flatten时字符串键转u32 HashMap的问题

核心原因

serde在处理#[serde(flatten)]嵌套结构体时,不会自动沿用直接结构体场景下的字符串键转数字键逻辑,需要显式指定转换规则。

方法1:使用serde_with工具库(推荐)

借助serde_with提供的现成转换函数,无需手动编写复杂逻辑:

  1. 添加依赖到Cargo.toml:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_with = "3.0"
  1. 修改结构体定义,给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:25:09