在 Rust 中反序列化平面 JSON,带有可选参数到嵌套结构和枚举
In rust deserialize flat JSON with optional parameter to a nested struct and enum
我正在尝试反序列化一些 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"
您可以在 Download
上使用 #[serde(flatten)]
属性:
#[derive(Deserialize, Debug)]
struct Download {
id: i32,
#[serde(flatten)]
status: Status,
}
这使您的所有测试都通过了:playground。
我正在尝试反序列化一些 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"
您可以在 Download
上使用 #[serde(flatten)]
属性:
#[derive(Deserialize, Debug)]
struct Download {
id: i32,
#[serde(flatten)]
status: Status,
}
这使您的所有测试都通过了:playground。