我正在尝试使用actix-web服务器作为小型堆栈的网关,以确保堆栈内部严格的数据格式,同时允许用户一些自由。为此,我希望将JSON字符串反序列化为结构体,然后验证它,再次序列化并发布到消息代理。主要的数据部分是包含整数、浮点数和日期时间的数组数组。我使用serde进行反序列化,并使用chrono处理日期时间。我尝试使用结构体结合枚举来允许不同的类型:
这里尝试两种不同的时间格式,并适用于DateTime字符串。
问题在于Serde将按顺序匹配数据与每个变量,成功反序列化的第一个变量将被返回。
发生了什么?我该如何解决?
我的想法是,要么我没有以正确的方式进行反序列化,要么我以某种方式“覆盖”了派生的反序列化。
请注意保留HTML标签。
#[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
,因此我添加了一个自定义模块,类似于 serde文档中描述的方式。
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);
}
}
这里尝试两种不同的时间格式,并适用于DateTime字符串。
问题在于Serde将按顺序匹配数据与每个变量,成功反序列化的第一个变量将被返回。
发生了什么?我该如何解决?
我的想法是,要么我没有以正确的方式进行反序列化,要么我以某种方式“覆盖”了派生的反序列化。
请注意保留HTML标签。
serde_with
中的DisplayFromStr
类型来执行此类转换任务。https://docs.rs/serde_with/1.9.4/serde_with/struct.DisplayFromStr.html - jonasbb