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

teh*_*wer 12 rust serde

我有以下对象:

{
  "data": {
    "id": 1,
    "name": "South America",
    "countries": {
      "data": [
        {
          "id": 122,
          "name": "Brazil",
          "capital": "Brasilia"
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

dto*_*nay 9

我将使用一个包装器结构来实现这一点,该结构可直接用于删除顶层嵌套,也可通过一个#[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(())
}
Run Code Online (Sandbox Code Playgroud)

在三个本质上不同的地方会出现微不足道的嵌套:

  1. 与其他字段相邻
  2. 本身位于顶层
  3. 本身低于顶层

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

要解决#1,请参阅使用 serde_json 解析时是否可以展平子对象字段?

  • 解决链接中的用例(反序列化实现)的最佳方法并不是解决此用例(不是反序列化实现)的最佳方法。请注意,存在三个本质上不同的地方,其中出现了无关紧要的嵌套 - 与其他字段相邻(在您的链接中观察到),其本身位于顶层,以及其本身位于顶层以下(均在本问题中观察到),并且它们需要三个不同的方法。 (4认同)