You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用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

火山引擎 最新活动