如何将多个键值条目的 JSON 对象反序列化为 Rust 中的自定义结构
How to deserialize JSON object of multiple key value entries to custom struct in Rust
我正在尝试将 JSON 中的一组未知键值样式标签反序列化到我的结构中。
这是我目前解析 JSON:
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use anyhow::Result;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
metadata: Metadata,
pub spec: Spec,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
name: String,
labels: HashMap<String, String>,
expires: String,
id: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Spec {
pub hostname: String,
}
fn main() -> Result<()> {
let json = r#"
[
{
"metadata": {
"name": "161bee39-cf07-4e31-90ba-6593c9f505cb",
"labels": {
"application": "api",
"owner": "team_x"
},
"expires": "2021-12-06T20:49:04.136656523Z",
"id": 1638823144137190452
},
"spec": {
"hostname": "host1.example.com"
}
},
{
"metadata": {
"name": "c1b3ee09-8e4a-49d4-93b8-95cbcb676f20",
"labels": {
"application": "database",
"owner": "team_y"
},
"expires": "2021-12-06T20:49:55.23841272Z",
"id": 1638823195247684748
},
"spec": {
"hostname": "host2.example.com"
}
}
]
"#;
let nodes: Vec<Node> = serde_json::from_str(json)?;
println!("{:?}", nodes);
Ok(())
}
该示例可以正常工作,但现在我想添加一个像这样的标签结构:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
name: String,
labels: Vec<Label>,
expires: String,
id: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Label {
key: String,
value: String,
}
这显然行不通,但我不确定如何从这里继续。根据我在此问题之前的研究,我知道您可以实现自定义反序列化器,但我无法找到如何正确地做到这一点。也许这也不是最好的方法,我没有看到明显的解决方案。
提前感谢任何示例或帮助。
根据 Stargateurs 的评论,serde_with 箱子提供了解决方案:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
name: String,
#[serde(with = "serde_with::rust::tuple_list_as_map")]
labels: Vec<Label>,
expires: String,
id: i64,
}
type Label = (String, String);
我正在尝试将 JSON 中的一组未知键值样式标签反序列化到我的结构中。
这是我目前解析 JSON:
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use anyhow::Result;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
metadata: Metadata,
pub spec: Spec,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
name: String,
labels: HashMap<String, String>,
expires: String,
id: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Spec {
pub hostname: String,
}
fn main() -> Result<()> {
let json = r#"
[
{
"metadata": {
"name": "161bee39-cf07-4e31-90ba-6593c9f505cb",
"labels": {
"application": "api",
"owner": "team_x"
},
"expires": "2021-12-06T20:49:04.136656523Z",
"id": 1638823144137190452
},
"spec": {
"hostname": "host1.example.com"
}
},
{
"metadata": {
"name": "c1b3ee09-8e4a-49d4-93b8-95cbcb676f20",
"labels": {
"application": "database",
"owner": "team_y"
},
"expires": "2021-12-06T20:49:55.23841272Z",
"id": 1638823195247684748
},
"spec": {
"hostname": "host2.example.com"
}
}
]
"#;
let nodes: Vec<Node> = serde_json::from_str(json)?;
println!("{:?}", nodes);
Ok(())
}
该示例可以正常工作,但现在我想添加一个像这样的标签结构:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
name: String,
labels: Vec<Label>,
expires: String,
id: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Label {
key: String,
value: String,
}
这显然行不通,但我不确定如何从这里继续。根据我在此问题之前的研究,我知道您可以实现自定义反序列化器,但我无法找到如何正确地做到这一点。也许这也不是最好的方法,我没有看到明显的解决方案。
提前感谢任何示例或帮助。
根据 Stargateurs 的评论,serde_with 箱子提供了解决方案:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
name: String,
#[serde(with = "serde_with::rust::tuple_list_as_map")]
labels: Vec<Label>,
expires: String,
id: i64,
}
type Label = (String, String);