【问题标题】:Deserialize variable meta object with serde使用 serde 反序列化变量元对象
【发布时间】:2020-05-07 09:28:01
【问题描述】:

我正在寻找一种优雅的方式来反序列化以下输入:

{
  "products": [

    {
      "id": 1,
      "ptype": "Clothes",
      "description": "some data about clothes",
      "metadata": {
        "colors" : ["blue", "green"],
        "web": false,
        "size": 2
      }
    },
    {
      "id": 4,
      "ptype": "Food",
      "description": "text for foods",
      "metadata": {
        "country": "France",
        "wine": true
      }
    },
    {
      "id": 12,
      "ptype": "EmptyPlaceholder",
      "description": "nothing at all",
      "metadata": {
      }
    }
  ]
}

json 包含一个产品数组。产品可以通过 ptype 字段来标识。根据字段的类型,元数据对象会有所不同。例如,如果 ptype 是 Food,那么 food 的元数据将是一个字符串(国家)和一个布尔值(wine)。所以产品有一些共同的字段,id,ptype和description以及一些元数据。我想在 Vec<Product> 中反序列化这个 JSON 文件。

到目前为止,我使用了以下代码:

use serde::{Deserialize};
use serde_json::Result;

#[derive(Deserialize, Debug)]
struct ClothesData {
    colors : Vec<String>,
    web : bool,
    size: u32,
}

#[derive(Deserialize, Debug)]
struct FoodData {
    country: String,
    wine: bool,
}

#[derive(Deserialize, Debug)]
struct EmptyData {

}

#[derive(Deserialize, Debug)]
enum Metadata {
    ClothesData,
    FoodData,
    EmptyData,
}

#[derive(Deserialize, Debug)]
enum  Ptype {
    Clothes,
    Food,
    EmptyPlaceholder
}

#[derive(Deserialize, Debug)]
struct Product {
    id: u32,
    ptype: Ptype,
    description: Option<String>,
    metadata: Metadata,

}

我不确定如何从这里开始,我想问一下 serde crate 是否可以“自动”执行此操作。

【问题讨论】:

    标签: rust serde


    【解决方案1】:

    这对应于"adjacently tagged" serde 枚举表示:

    use serde::Deserialize;
    use serde_json::Result;
    
    #[derive(Deserialize, Debug)]
    struct Clothes {
        colors: Vec<String>,
        web: bool,
        size: u32,
    }
    
    #[derive(Deserialize, Debug)]
    struct Food {
        country: String,
        wine: bool,
    }
    
    #[derive(Deserialize, Debug)]
    struct Empty {}
    
    #[derive(Deserialize, Debug)]
    #[serde(tag = "ptype", content = "metadata")]
    enum Kind {
        Clothes(Clothes),
        Food(Food),
        EmptyPlaceholder(Empty),
    }
    
    #[derive(Deserialize, Debug)]
    struct Product {
        id: u32,
        description: Option<String>,
        #[serde(flatten)]
        kind: Kind,
    }
    
    #[derive(Deserialize, Debug)]
    struct Root {
        products: Vec<Product>,
    }
    
    fn main() -> Result<()> {
        let data = r#"
        {
            "products": [
    
                {
                  "id": 1,
                  "ptype": "Clothes",
                  "description": "some data about clothes",
                  "metadata": {
                    "colors" : ["blue", "green"],
                    "web": false,
                    "size": 2
                  }
                },
                {
                  "id": 4,
                  "ptype": "Food",
                  "description": "text for foods",
                  "metadata": {
                    "country": "France",
                    "wine": true
                  }
                },
                {
                  "id": 12,
                  "ptype": "EmptyPlaceholder",
                  "description": "nothing at all",
                  "metadata": {
                  }
                }
            ]
        }"#;
    
        let root: Root = serde_json::from_str(data)?;
        println!("{:#?}", root);
    
        Ok(())
    }
    

    【讨论】:

      猜你喜欢
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多