在使用Serde反序列化对象时,有没有办法省略包装器/根对象?

问题描述 投票:1回答:1

我有以下对象:

{
  "data": {
    "id": 1,
    "name": "South America",
    "countries": {
      "data": [
        {
          "id": 122,
          "name": "Brazil",
          "capital": "Brasilia"
        }
      ]
    }
  }
}

我想定义两个结构,ContinentCountry,省略不增加价值的data包装。

rust serde
1个回答
3
投票

我将使用包装器结构来实现它,该结构可以直接用于删除顶层嵌套以及通过#[serde(with = "...")]属性来消除反序列化数据结构中的嵌套级别。


use serde::{Deserialize, Deserializer};

#[derive(Deserialize, Debug)]
struct Continent {
    id: u64,
    name: String,
    #[serde(with = "Wrapper")]
    countries: Vec<Country>,
}

#[derive(Deserialize, Debug)]
struct Country {
    id: u64,
    name: String,
    capital: String,
}

#[derive(Deserialize)]
struct Wrapper<T> {
    data: T,
}

impl<T> Wrapper<T> {
    fn deserialize<'de, D>(deserializer: D) -> Result<T, D::Error>
    where
        T: Deserialize<'de>,
        D: Deserializer<'de>,
    {
        let wrapper = <Self as Deserialize>::deserialize(deserializer)?;
        Ok(wrapper.data)
    }
}

fn main() -> serde_json::Result<()> {
    let j = r#"
        {
          "data": {
            "id": 1,
            "name": "South America",
            "countries": {
              "data": [
                {
                  "id": 122,
                  "name": "Brazil",
                  "capital": "Brasilia"
                }
              ]
            }
          }
        }"#;

    let wrapper: Wrapper<Continent> = serde_json::from_str(j)?;
    println!("{:#?}", wrapper.data);

    Ok(())
}

有三个实质上不同的地方出现无关紧要的嵌套:

  1. 与其他领域相邻
  2. 本身就处于顶层
  3. 本身低于顶级水平

这三者都需要不同的方法。在这个问题中观察到#2和#3。

要解决#1,请参阅Is it possible to flatten sub-object fields while parsing with serde_json?

© www.soinside.com 2019 - 2024. All rights reserved.