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

如何让Serde按照结构体定义的顺序反序列化对象?

确保Serde反序列化按结构体定义顺序处理字段

问题描述

我需要把字段值存储到全局上下文中,但当JSON对象的字段顺序和结构体定义不一致时,操作无法正常执行。比如下面的代码里,JSON先出现b再出现a,反序列化时会先处理b,但我希望严格按照结构体定义的顺序(先a后b)来处理。

示例代码:

use serde::{Deserialize, Deserializer};
use std::error::Error;

fn a_deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
    D: Deserializer<'de>,
{
    let num = Deserialize::deserialize(deserializer)?;
    println!("a");
    Ok(num)
}

fn b_deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
    D: Deserializer<'de>,
{
    let num = Deserialize::deserialize(deserializer)?;
    println!("b");
    Ok(num)
}

#[derive(Deserialize)]
struct Test {
    #[serde(deserialize_with = "a_deserialize")]
    a: u32,
    #[serde(deserialize_with = "b_deserialize")]
    b: u32,
}

fn main() -> Result<(), Box<dyn Error>> {
    // JSON字段顺序是b在前,a在后
    let str = "{ \"b\": 1, \"a\": 2 }";

    let test: Test = serde_json::from_str(&str)?;
    // 当前输出是b然后a,但需要输出a然后b

    Ok(())
}

解决方案

要强制按结构体定义的顺序反序列化字段,你需要手动实现Deserialize trait,这样就能完全控制字段的处理顺序。具体步骤如下:

  1. 先把JSON解析成serde_json::Value,获取所有字段的值;
  2. 按照结构体定义的顺序,逐个提取对应字段的值并调用自定义反序列化函数;
  3. 组装成目标结构体实例。

修改后的代码:

use serde::{Deserialize, Deserializer};
use serde_json::Value;
use std::error::Error;

fn a_deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
    D: Deserializer<'de>,
{
    let num = Deserialize::deserialize(deserializer)?;
    println!("a");
    Ok(num)
}

fn b_deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
    D: Deserializer<'de>,
{
    let num = Deserialize::deserialize(deserializer)?;
    println!("b");
    Ok(num)
}

struct Test {
    a: u32,
    b: u32,
}

impl<'de> Deserialize<'de> for Test {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // 先把整个JSON解析成Value
        let value = Value::deserialize(deserializer)?;
        
        // 按结构体定义顺序,先处理a,再处理b
        let a = a_deserialize(&value["a"])?;
        let b = b_deserialize(&value["b"])?;
        
        Ok(Test { a, b })
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let str = "{ \"b\": 1, \"a\": 2 }";

    let test: Test = serde_json::from_str(&str)?;
    // 现在输出是a然后b,符合预期

    Ok(())
}

补充说明

  • 如果需要处理可选字段或默认值,可以用value.get("a")替代直接索引,再处理None的情况;
  • 这种方法完全绕过了Serde默认的字段顺序处理逻辑,确保严格按照你定义的顺序执行反序列化操作,适合依赖处理顺序的场景(比如全局上下文的状态维护)。

内容的提问来源于stack exchange,提问作者Sam Denty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:57:27