【问题标题】:In rust deserialize flat JSON with optional parameter to a nested struct and enum在 rust 中,将带有可选参数的平面 JSON 反序列化为嵌套结构和枚举
【发布时间】:2021-09-26 16:24:17
【问题描述】:

我正在尝试反序列化一些 JSON:{"id":1,"status":"Failed","cause":"Error"},其中状态可以是“正在执行”、“成功”或“失败”之一,我的问题是,如果状态为“失败”,我只会得到“原因” ”。

我不希望原因是Option<String>,因为如果状态为“失败”,我总是会得到原因,而如果状态是“正在执行”或“成功”,我永远不会得到原因。我宁愿有类似的东西:

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Download {
    id: i32,
    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();
    }
}

在上面的代码片段中,所有 status_from 测试都通过了,而 download_from 测试失败了。如果我从状态中删除 #[serde(tag = "status")] 属性,那么只有 download_from_executing 和 download_from_succeeded 通过。

我只关心能够反序列化下载结构。

当我有一个状态为“失败”和原因的 JSON 正文时,我想找到一组正确的 serde 属性来反序列化下载结构。

我的 Cargo.toml:

[package]
name = "example"
version = "0.1.0"
edition = "2018"

[dependencies]
serde = { version = "1.0.130", features = ["derive"] }
serde_json = "1.0.68"

【问题讨论】:

  • 您可以编写自己的反序列化器,然后反序列化为扁平结构,然后嵌套到最终结构中。

标签: rust serde serde-json


【解决方案1】:

您可以在Download 上使用#[serde(flatten)] 属性:

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

这将使您的所有测试都通过:playground

【讨论】:

  • 啊,谢谢,我误读了文档,并认为 flatten 只能应用于结构,但它在结构内说。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-21
  • 2023-02-22
  • 2015-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多