【问题标题】:How to reduce/flatten an array of union type objects with serde_json?如何使用 serde_json 减少/展平联合类型对象数组?
【发布时间】:2022-10-02 08:02:46
【问题描述】:

我正在尝试找到一种反序列化以下 JSON 数据的有效方法:

{
    \"filters\": [
        {
            \"filterType\": \"MIN_FILTER\",
            \"min\": 2
        },
        {
            \"filterType\": \"MAX_FILTER\",
            \"max\": 10
        },
        {
            \"filterType\": \"PRIORITY_FILTER\",
            \"priority\": \"High\"
        }
    ]
}

变成这样:

{
    \"filters\": {
        \"min\": 2,
        \"max:\": 10,
        \"priority\": \"High\"
    }
}

我刚开始学习 Rust 和 Serde,但到目前为止我能想到的最好的方法是这个自定义的 Deserializer 实现,它首先将每个过滤器反序列化为一个通用的过滤器,其中包含所有可能具有 Option 值的字段:

extern crate serde;
extern crate serde_json;

use serde::{Deserialize, Deserializer};

#[derive(Deserialize, Debug)]
pub struct Object {
    filters: Filters,
}

#[derive(Debug)]
pub struct Filters {
    min: u32,
    max: u32,
    priority: String,
}

impl<\'de> Deserialize<\'de> for Filters {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<\'de>,
    {
        #[derive(Deserialize)]
        pub struct GenericFilter {
            filterType: String,
            priority: Option<String>,
            min: Option<u32>,
            max: Option<u32>,
        }

        let filters = Vec::<GenericFilter>::deserialize(deserializer)?;
        let mut priority: Option<&String> = None;
        let mut min: Option<u32> = None;
        let mut max: Option<u32> = None;

        for item in filters.iter() {
            if item.filterType == \"PRIORITY_FILTER\" {
                priority = item.priority.as_ref();
            }
            if item.filterType == \"MIN_FILTER\" {
                min = item.min;
            }
            if item.filterType == \"MAX_FILTER\" {
                max = item.max;
            }
        }

        Ok(Filters {
            priority: priority.unwrap().to_owned(),
            min: min.unwrap(),
            max: max.unwrap(),
        })
    }
}

fn main() {
    let json = r#\"
        {
            \"filters\": [
                {
                    \"filterType\": \"MIN_FILTER\",
                    \"min\": 2
                },
                {
                    \"filterType\": \"MAX_FILTER\",
                    \"max\": 10
                },
                {
                    \"filterType\": \"PRIORITY_FILTER\",
                    \"priority\": \"High\"
                }
            ]
        }
    \"#;

    println!(
        \"Deserialized = {:#?}\",
        serde_json::from_str::<Object>(&json)
    );
}

这只是感觉不对,也许有人对此有更好的解决方案? :)

  • 一方面,可能想尝试 match 而不是 3 个 if 语句。此外,这 3 个 if 语句应该真的是 if-elseif-else :)

标签: json rust serde


【解决方案1】:

我会将反序列化和实际数据的构造分开。反序列化一个Vec&lt;GenericFilter&gt;,然后有一个单独的函数从它构造Filters

【讨论】:

    猜你喜欢
    • 2022-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 2017-06-05
    • 1970-01-01
    • 2021-04-05
    • 2019-03-26
    相关资源
    最近更新 更多