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

Rust中如何将带可选参数的扁平JSON反序列化为嵌套结构体与枚举

解决方案

问题原因

你当前的写法中,标记了#[serde(tag = "status")]的Status枚举作为Download的嵌套字段时,serde默认期望status字段对应的值是一个包含status标签和cause(失败场景下)的嵌套对象,但实际你的JSON结构里status、cause都是和id平级的顶级字段,字段匹配逻辑错位导致反序列化失败。

修改方法

仅需给Download结构体的status字段添加#[serde(flatten)]属性即可,修改后的完整代码如下:

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Download {
    id: i32,
    #[serde(flatten)]
    status: Status,
}

#[derive(Deserialize, Debug)]
#[serde(tag = "status")]
enum Status {
    Executing,
    Successful,
    Failed {
        cause: String
    },
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn status_from_executing() {
        let s = r#"{"status":"Executing"}"#;
        serde_json::from_str::<Status>(s).unwrap();
    }

    #[test]
    fn status_from_succeeded() {
        let s = r#"{"status":"Successful"}"#;
        serde_json::from_str::<Status>(s).unwrap();
    }

    #[test]
    fn status_from_failed() {
        let s = r#"{"status":"Failed","cause":"Bad thing"}"#;
        serde_json::from_str::<Status>(s).unwrap();
    }

    #[test]
    fn download_from_executing() {
        let s = r#"{"id":1,"status":"Executing"}"#;
        serde_json::from_str::<Download>(s).unwrap();
    }

    #[test]
    fn download_from_succeeded() {
        let s = r#"{"id":1,"status":"Successful"}"#;
        serde_json::from_str::<Download>(s).unwrap();
    }

    #[test]
    fn download_from_failed() {
        let s = r#"{"id":1,"status":"Failed","cause":"Bad thing"}"#;
        serde_json::from_str::<Download>(s).unwrap();
    }
}

#[serde(flatten)]的作用是将枚举内部需要匹配的字段(包括status标签、Failed变体的cause字段)提升到和外层Download的id字段同级,反序列化时直接从JSON顶级字段匹配枚举需要的内容,完美适配你现有的JSON结构。修改后所有测试用例均可正常通过,且保留了类型安全的优势,不需要将cause定义为Option<String>。


内容的提问来源于stack exchange,提问作者Jack Johnstone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 03:18:02