【问题标题】:Rust Serde - Is it possible to map json data the could be in two different layouts back to a single struct?Rust Serde - 是否可以将可能在两种不同布局中的 json 数据映射回单个结构?
【发布时间】:2020-03-26 22:48:44
【问题描述】:

我试图映射到我的结构的数据有两种格式:

使用card_faces,当卡片有多个面时:

{
  "object": "card",
  "id": "some_id",
  "lang": "en",
  "released_at": "2012-02-03",
  "card_faces": [
    {
      "name": "some_name",
      "cost": "5",
      "ctype": "some_type",
      "colors": [
        "R",
        "B"
      ]
    },
    {
      "name": "another_name",
      "cost": "",
      "ctype": "another_type",
      "colors": [
        "R",
        "B"
      ]
    }
  ],
  "set_code": "some_code"
}

并且没有card_faces,当只有一张人脸时(人脸字段只是放在根中):

{
  "object": "card",
  "id": "some_id",
  "lang": "en",
  "released_at": "2012-02-03",
  "name": "some_name",
  "cost": "5",
  "ctype": "some_type",
  "colors": [
    "R",
    "B"
  ],
  "set_code": "some_code"
}

我希望我的结构总是有一个Vec<CardFace> 字段。比如:

#[derive(Deserialize)]
struct Card {
  object: String,
  id: String,
  lang: String,
  released_at: String,
  faces: Vec<CardFace>,
  set_code: String,
}

是否可以反序列化这些对象并将面部字段强制转换为所需的格式,或者我需要在反序列化之前操作 json 吗?

【问题讨论】:

  • 我只是想补充一点,像这样设计 JSON 的人一定讨厌其他人:请不要那样做。

标签: json rust deserialization json-deserialization serde


【解决方案1】:

我会使用中介enum

#[derive(Deserialize)]
#[serde(untagged)]
enum CardTmpDeser {
    Card {
        object: String,
        id: String,
        lang: String,
        released_at: String,
        card_faces: Vec<CardFace>,
        set_code: String,
    },
    SingleCard {
        object: String,
        id: String,
        lang: String,
        released_at: String,
        name: String,
        cost: String,
        ctype: String,
        colors: Vec<String>,
        set_code: String,
    },
}

使用#[serde(untagged)] 属性,您可以透明地反序列化您拥有的两种数据。

现在只需使用#[serde(from = "CardTmpDeser")] 标记您的实际结构:

#[derive(Debug, Deserialize)]
#[serde(from = "CardTmpDeser")]
pub struct Card {
    object: String,
    id: String,
    lang: String,
    released_at: String,
    card_faces: Vec<CardFace>,
    set_code: String,
}

并为Card 实施From&lt;CardTmpDeser&gt;,你就可以开始了! serde 将使用 CardTmpDeser 自动反序列化您的数据,但会透明地将其转换为您的最终类型。

(Permalink to the playground with full working example)

【讨论】:

    猜你喜欢
    • 2017-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    相关资源
    最近更新 更多