使用 serde Rust 将数据从记录转置到没有中间结构的列

Transpose data from records to columns without intermediate struct using serde Rust

我有两种不同的结构化数据:

1: JSON

{
    "key1": 40,
    "key2": 50
{,
{
    "key1": 41,
    "key2": 51
}

2:嵌套数组

[[40,50],[41,51]]

目标是将此数据(我收到的都是 Strings)反序列化为如下所示的结构:

struct data {
    key1: Vec<i8>,      // -> [40,41]
    key2: Vec<i8>       // -> [50,51]
}

我已经有 2 种方法来反序列化每种类型的数据,但问题是对于第一种,我必须创建一个中间 Struct 并将它们收集在 Vec 中然后迭代这个 Vec 将每个元素推到最终 Struct 中的特定 Vecs。 对于第二个,我反序列化为 Vec<Vec<i8>>,然后再次迭代逐个元素转置为最终的 Struct

我通读了所有 serde 文档并试图找到示例,但无法找到一种方法直接推送到 Struct 的最后 Vecs 而无需中间件步。 serde 支持吗?如果有,它是如何实现的?

为此,您需要为数组自定义访问者。下面是一个有效的实现。

请注意,虽然我们使用了额外的枚举 InnerData,但它不需要任何额外的分配,因为该结构仅在堆栈中使用。对于外部数组 InnerData 的每个元素都将被反序列化,并将其字段推送到 Data 结构的字段。

#[serde(untagged)] 允许从平面变体中反序列化枚举(无需在 json 中指定 Map 或 Array)。

也不是,要使用这种类型的反序列化,你需要特别让Deserializer知道使用哪个Visitor。如果您的结构是另一个结构的字段之一,您可以使用 #[serde(deserialize_with = ...)] 属性指定它。

use serde::de;
use serde::de::Deserializer;
use serde::Deserialize;

const A: &str = "[{\"key1\": 40, \"key2\": 50}, {\"key1\": 41, \"key2\": 51}]";
const B: &str = "[[40, 50], [41, 51]]";

#[derive(Debug, Deserialize)]
struct Data {
    key1: Vec<i8>,
    key2: Vec<i8>,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum InnerData {
    Map { key1: i8, key2: i8 },
    Array(i8, i8),
}

struct DataVisitor;

impl<'de> de::Visitor<'de> for DataVisitor {
    type Value = Data;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "invalid input")
    }

    fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
        let mut result = Data {
            key1: vec![],
            key2: vec![],
        };
        while let Some(inner) = seq.next_element::<InnerData>()? {
            let (k1, k2) = match inner {
                InnerData::Map { key1, key2 } => (key1, key2),
                InnerData::Array(key1, key2) => (key1, key2),
            };

            result.key1.push(k1);
            result.key2.push(k2);
        }

        Ok(result)
    }
}

fn main() {
    let mut deserializer = serde_json::Deserializer::from_str(A);
    println!("{:?}", deserializer.deserialize_seq(DataVisitor {}));

    let mut deserializer = serde_json::Deserializer::from_str(B);
    println!("{:?}", deserializer.deserialize_seq(DataVisitor {}));
}

Fiddle: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f921adbb490970eb9a8b5ef5f9ab49d0