1

我遇到的一个 API 的 JSON 结构很差。有人认为发回如下所示的列表是个好主意

features: [
  "First one",
  "second one",
  {
    "feature": "third one",
    "hasAdditionalImpact": true
  },
  "forth one"
]

我已经想出了一种这些数据放入结构中的方法,但这很有效:

struct MyStruct {
    SensibleData: String,
    SensibleTruthy: bool,
    features: serde_json::Value,
}

这无助于我规范化和验证数据。

有没有一种好方法可以将第一个对象变成类似的东西

features: [
  {
    "feature": "First one",
    "hasAdditionalImpact": false
  },
  {
    "feature": "second one",
    "hasAdditonalImpact": false
  },
  {
    "feature": "third one",
    "hasAdditionalImpact": true
  },
  {
    "feature": "forth one",
    "hasAdditionalImpact": false
  }
]

我看到type_name可能可用于检查类型并在它被解析后进行后处理serde_json,但我也看到这type_name是出于诊断目的,所以我不想将其用于此目的。

4

1 回答 1

3

看起来您的 JSON 中的功能有两种形式;显式对象和简化形式,其中某些字段默认或未命名。您可以使用这样的 eum 对其进行建模:

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Feature {
    Simple(String),
    Explicit {
        feature: String,
        #[serde(rename = "hasAdditionalImpact")]
        has_additional_impact: bool,
    }
}

操场

#[serde(untagged)]属性意味着它将尝试按顺序反序列化到每个变体中,直到一个成功。


如果枚举会很烦人,您可以将它们全部转换为具有默认值的相同结构,使用#[serde(from)]并提供From转换:

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum FeatureSource {
    Simple(String),
    Explicit {
        feature: String,
        #[serde(rename = "hasAdditionalImpact")]
        has_additional_impact: bool,
    },
}

#[derive(Deserialize, Debug)]
#[serde(from = "FeatureSource")]
struct Feature {
    feature: String,
    has_additional_impact: bool,
}

impl From<FeatureSource> for Feature {
    fn from(other: FeatureSource) -> Feature {
        match other {
            FeatureSource::Simple(feature) => Feature {
                feature,
                has_additional_impact: false,
            },
            FeatureSource::Explicit {
                feature,
                has_additional_impact,
            } => Feature {
                feature,
                has_additional_impact,
            },
        }
    }
}

操场

FeatureSource仅用作中间表示并Feature在其余代码看到它之前转换为。

于 2021-07-02T21:02:32.333 回答