我试图使用actix服务器作为通向小堆栈的网关,以保证堆栈内有严格的数据格式,同时允许用户有一些自由。
为此,我希望将JSON字符串反序列化到结构中,然后验证它,再次序列化它,并在message上发布它。数据的主要部分是包含整数、浮点数和日期时间的数组数组。我使用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,所以我为该模块添加了一个自定义模块,类似于如何描述在农庄的医生。
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字符串。
问题
#[derive(Serialize, Deserialize)]、#[serde(untagged)]和#[serde(with)]的结合似乎做了一些意想不到的事情。serde:from\_str(...)试图用我的自定义deserialize函数反序列化数组中的每个条目。我希望它要么尝试先反序列化为ValueType::I32,然后再继续下一个条目,就像医生们说的:
Serde将尝试按照顺序将数据与每个变体匹配,第一个反序列化成功的是返回的变量。
所发生的情况是将自定义deserialize应用于例如"0"失败和反序列化停止。
到底怎么回事?我该怎么解决呢?
我的想法是,我要么没有以错误的方式反序列化,要么我用自己的方法“覆盖”派生反序列化。
发布于 2021-07-09 12:41:42
发布于 2021-07-09 10:43:02
许多板条箱将实现serde和其他公共实用程序板条箱,但它们将保留为可选特性。这有助于在编译时节省时间。您可以通过查看Cargo.toml文件来检查机箱,查看它是否有特性或是否包含依赖项,但将其标记为可选。
在您的例子中,我可以转到chrono on crates.io并选择存储库链接来查看机箱的源代码。在Cargo.toml文件中,我可以看到使用了serde,但默认情况下没有启用。
[features]
default = ["clock", "std", "oldtime"]
alloc = []
std = []
clock = ["libc", "std", "winapi"]
oldtime = ["time"]
wasmbind = ["wasm-bindgen", "js-sys"]
unstable-locales = ["pure-rust-locales", "alloc"]
__internal_bench = []
__doctest = []
[depenencies]
...
serde = { version = "1.0.99", default-features = false, optional = true }要启用它,您可以进入项目的Cargo.toml并将其作为特性添加到chrono中。
[depenencies]
chrono = { version: "0.4.19", features = ["serde"] }或者,chrono列出了一些(但不是全部?)它们在文档中的可选特性。然而,并不是所有的板条箱都这样做,而且文档有时会过时,所以我通常更喜欢手动方法。
至于枚举上的deserialize_with untagged 和untagged之间的交互问题,我认为您的代码没有任何问题。这可能是服务器中的一个bug,所以我建议您在 serde储存库 上创建一个问题,这样他们就可以进一步研究为什么会发生此错误。
https://stackoverflow.com/questions/68314646
复制相似问题