使用 serde Rust 将数据从记录转置到没有中间结构的列
Posted
技术标签:
【中文标题】使用 serde Rust 将数据从记录转置到没有中间结构的列【英文标题】:Transpose data from records to columns without intermediate struct using serde Rust 【发布时间】:2021-11-12 18:32:52 【问题描述】:我有两种不同的数据结构:
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]
我已经有两种方法来反序列化每种类型的数据,但问题是对于第一种方法,我必须创建一个中间 Struct
并将它们收集到 Vec
中,然后迭代这个 Vec
在最终的Struct
中将每个元素推送到其特定的Vec
s。
对于第二个,我反序列化为Vec<Vec<i8>>
,然后再次迭代,逐个元素地转换为最终的Struct
。
我通读了所有serde
文档并试图找到示例,但找不到直接推送到Struct
的最终Vec
s 的方法,而无需中间步骤。
serde
支持这个吗?如果有,它是如何实现的?
【问题讨论】:
【参考方案1】:为此,您需要为您的数组提供一个自定义访问者。下面是一个有效的实现。
请注意,虽然我们使用了额外的枚举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 ));
小提琴:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f921adbb490970eb9a8b5ef5f9ab49d0
【讨论】:
也许你可以解释一下这些反序列化器会做什么,如何使用它们,或者更好的是提供代码来说明要做什么。 Maxim,你能添加一段代码来演示一下吗? @mbfernan 我对反序列化器实际上是错误的。在摆弄了一下之后,我得出了可行的解决方案。我改了答案,也给代码加了一些解释。以上是关于使用 serde Rust 将数据从记录转置到没有中间结构的列的主要内容,如果未能解决你的问题,请参考以下文章