【问题标题】:Deserialize map with empty objects as values使用空对象作为值反序列化映射
【发布时间】:2021-08-19 09:58:26
【问题描述】:

我有 json 文档,其中可能包含具有引用空对象的键的对象,像这样

{
  "mylist": {
    "foo": {},
    "bar": {}
  }
}

我想将它们反序列化为字符串的 Vec(稍后再将其序列化回上述格式)

pub struct MyStruct {
  #[serde(skip_serializing_if = "Option::is_none")]
  pub my_list: Option<Vec<String>>; // should contain "foo", "bar"
}

如何使用 serde 做到这一点?

【问题讨论】:

  • 呃,如果 foo 或 bar 对象不为空怎么办?无论如何,您似乎需要自己实现反序列化。
  • 它们永远是空的
  • 如果它们永远是空的,那么实际上有一个数组不是更简单吗? "mylist":["foo", "bar"]?
  • 我无法控制文档格式

标签: rust serde


【解决方案1】:

您需要编写自己的反序列化方法,并使用deserialize_with 或直接为您的类型实现它:

use serde::Deserialize; // 1.0.127
use serde::Deserializer;
use serde_json;
use std::collections::HashMap; // 1.0.66

#[derive(Deserialize, Debug)]
pub struct MyStruct {
    #[serde(deserialize_with = "deserialize_as_vec", alias = "mylist")]
    pub my_list: Vec<String>,
}

#[derive(Deserialize)]
struct DesHelper {}

fn deserialize_as_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
    D: Deserializer<'de>,
{
    let data: HashMap<String, DesHelper> = HashMap::<String, DesHelper>::deserialize(deserializer)?;
    Ok(data.keys().cloned().collect())
}

fn main() {
    let example = r#"
{
  "mylist": {
    "foo": {},
    "bar": {}
  }
}"#;

    let deserialized: MyStruct = serde_json::from_str(&example).unwrap();
    println!("{:?}", &deserialized);
}

结果:

MyStruct { my_list: ["foo", "bar"] }

Playground

注意对它们的空白部分使用了辅助结构。代码非常简单,您基本上是反序列化地图,然后获取您需要的键。

【讨论】:

    猜你喜欢
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 2020-06-24
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多