serialization - 使用#[serde(untagged)] 和#[serde(with

我正在尝试使用 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 字符串。

问题

`#[derive(Serialize, Deserialize)]`、`#[serde(untagged)]` 和 `#[serde(with)]` 的组合似乎做了一些意想不到的事情。 `serde:from_str(...)` 尝试使用我自定义的 `deserialize` 函数反序列化数组中的每个条目。 我希望它首先尝试反序列化为“ValueType::I32”,成功并继续下一个条目,如 [文档](https://serde.rs/enum-representations.html) 所说:

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/

相关文章:

django - 如何在基于 Django 类的 View 中更改模板

python - 我的损失函数在训练期间没有得到更小的值

reactjs - 如何在 primereact 中拥有主题切换器

sass - Stylelint 禁用规则, "no-descending-specificity"

rust - 如何正确处理 Warp 路由的错误

python - 通用协议(protocol) : mypy error: Argument 1 h

python - 多次拟合时 keras fit() 的历史

kubernetes - 部署后如何在 kubernetes 中删除 Traefik 2.0 中间件

sql - 如何获得日期 + 时间的确定性计算值

python - numpy 中如何实现多维数组切片/索引?