我正在尝试使用 actix-web 服务器作为通往小型堆栈的网关,以保证堆栈内部的数据格式严格,同时为用户提供一些自由。
为此,我想将 JSON 字符串反序列化为结构,然后对其进行验证、再次序列化并将其发布到消息代理上。数据的主要部分是包含整数、 float 和日期时间的数组数组。我使用 serde 进行反序列化,使用 chrono 来处理日期时间。
我尝试使用结构和枚举来允许不同的类型:
#[derive(Serialize, Deserialize)]
pub struct Data {
pub column_names: Option<Vec<String>>,
pub values: Vec<Vec<ValueType>>,
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum ValueType {
I32(i32),
F64(f64),
#[serde(with = "datetime_handler")]
Dt(DateTime<Utc>),
}
自 chrono::DateTime<T>
不执行Serialize
,我为此添加了一个自定义模块,类似于它的描述 in the serde docs .
mod datetime_handler {
use chrono::{DateTime, TimeZone, Utc};
use serde::{self, Deserialize, Deserializer, Serializer};
pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = dt.to_rfc3339();
serializer.serialize_str(&s)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
D: Deserializer<'de>,
{
println!("Checkpoint 1");
let s = String::deserialize(deserializer)?;
println!("{}", s);
println!("Checkpoint 2");
let err1 = match DateTime::parse_from_rfc3339(&s) {
Ok(dt) => return Ok(dt.with_timezone(&Utc)),
Err(e) => Err(e),
};
println!("Checkpoint 3");
const FORMAT1: &'static str = "%Y-%m-%d %H:%M:%S";
match Utc.datetime_from_str(&s, FORMAT1) {
Ok(dt) => return Ok(dt.with_timezone(&Utc)),
Err(e) => println!("{}", e), // return first error not second if both fail
};
println!("Checkpoint 4");
return err1.map_err(serde::de::Error::custom);
}
}
这会依次尝试 2 种不同的时间格式,并且适用于 DateTime 字符串。
Serde will try to match the data against each variant in order and the first one that deserializes successfully is the one returned.
发生的是自定义 deserialize
适用于例如"0"
失败,反序列化停止。
这是怎么回事?我该如何解决?
我的想法是,我要么未能以错误的方式反序列化,要么我以某种方式“覆盖”了派生的反序列化。
最佳答案
@jonasbb 帮助我意识到代码在使用 [0,16.9,"2020-12-23 00:23:14"]
时有效,但在尝试反序列化 [ “0”,“16.9”,“2020-12-23 00:23:14”]
。默认情况下,Serde 不会序列化字符串中的数字,对 I32 和 F64 的尝试只会默默地失败。这在本 serde-issue 中讨论可以使用非官方 serde-aux 解决 crate 。
关于serialization - 使用#[serde(untagged)] 和#[serde(with)] 的组合反序列化枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68314646/