如何使用Serde将嵌套JSON反序列化为单层结构体?
如何使用Serde将嵌套JSON反序列化为单层结构体?
当然可以啦!我之前也碰到过这种不想为嵌套字段额外定义结构体的需求,Serde提供了好几种优雅的解决方案,下面给你详细拆解:
首先先明确你的需求:
要反序列化的JSON:
{ "name": "Name", "server": { "name": "Server" } }目标单层结构体:
struct Character { name: String, server: String, }
方法一:用serde_with库快速实现(最简洁)
如果不介意加个轻量依赖,serde_with库提供的Path功能可以直接帮你提取嵌套字段,不用写任何额外逻辑。
首先在Cargo.toml里添加依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_with = "3.0"
然后修改你的结构体,加上serde_as属性和Path注解:
use serde::Deserialize; use serde_with::serde_as; use serde_with::Path; #[serde_as] #[derive(Debug, Deserialize)] struct Character { name: String, // 直接指定从JSON的`server.name`路径提取值 #[serde_as(as = "Path<'server.name>")] server: String, } fn main() { let json = r#"{ "name": "Name", "server": { "name": "Server" } }"#; let character: Character = serde_json::from_str(json).unwrap(); println!("{:?}", character); // 输出结果:Character { name: "Name", server: "Server" } }
这种方式代码最简洁,完全不用处理嵌套结构,serde_with帮你搞定了所有细节。
方法二:手动实现反序列化(无额外依赖)
如果不想加新依赖,用Serde原生功能也能实现,核心思路是定义一个临时的嵌套结构体来匹配JSON结构,反序列化后再转成目标的单层结构体。
代码示例:
use serde::de::Deserializer; use serde::Deserialize; #[derive(Debug)] struct Character { name: String, server: String, } impl<'de> Deserialize<'de> for Character { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { // 定义临时嵌套结构体,完全匹配JSON的结构 #[derive(Deserialize)] struct TempCharacter { name: String, server: TempServer, } #[derive(Deserialize)] struct TempServer { name: String, } // 先反序列化到临时结构体,再转换为目标结构体 let temp = TempCharacter::deserialize(deserializer)?; Ok(Character { name: temp.name, server: temp.server.name, }) } } fn main() { let json = r#"{ "name": "Name", "server": { "name": "Server" } }"#; let character: Character = serde_json::from_str(json).unwrap(); println!("{:?}", character); }
这个方法完全依赖Serde原生功能,没有额外依赖,适合对依赖体积有要求的场景。
方法三:动态解析(适合简单场景)
如果你的需求非常简单,也可以先把JSON解析成serde_json::Value,再手动提取嵌套字段。不过这种方法需要自己处理字段不存在或类型不匹配的错误,健壮性稍差:
use serde_json::Value; #[derive(Debug)] struct Character { name: String, server: String, } fn main() { let json = r#"{ "name": "Name", "server": { "name": "Server" } }"#; let value: Value = serde_json::from_str(json).unwrap(); // 手动提取字段,注意这里用unwrap是简化示例,实际项目要处理错误 let character = Character { name: value["name"].as_str().unwrap().to_string(), server: value["server"]["name"].as_str().unwrap().to_string(), }; println!("{:?}", character); }
这个方法适合快速原型或者字段结构固定且不会变化的简单场景。
内容来源于stack exchange




