当前位置: 首页 > 知识库问答 >
问题:

使用35;[serde(Untaged)]和#[serde(with)]的组合反序列化枚举

庾才
2023-03-14

我正在尝试使用actix-web服务器作为小型堆栈的网关,以保证堆栈内部的严格数据格式,同时为用户提供一些自由。

为此,我想将 JSON 字符串反序列化到结构中,然后对其进行验证,再次序列化它并将其发布在消息代理上。数据的主要部分是一个数组,其中包含整数,浮点数和日期时间。我使用 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>),
}

由于<code>chrono::DateTime

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);
    }
}

这将一个接一个地尝试两种不同的时间格式,并适用于日期时间字符串。

Serde 将尝试按顺序将数据与每个变体进行匹配,第一个成功反序列化的数据是返回的变体。

发生的情况是自定义的< code >反序列化应用于例如< code >“0”失败,反序列化停止。

这是怎么回事?我怎么解决?

我的想法是,我要么以错误的方式反序列化失败,要么以某种方式用我自己的方式“覆盖”了派生的反序列化。

共有2个答案

封瑞
2023-03-14

许多板条箱将实现< code>serde和其他常见的实用板条箱,但将它们作为可选功能。这有助于编译时节省时间。您可以通过查看Cargo.toml文件来检查一个板条箱,以查看是否有该板条箱的某个功能,或者是否包含了依赖项但标记为可选。

对于您的情况,我可以访问crates.io上的< code>chrono,并选择存储库链接来查看crates的源代码。在< code>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 }

要启用它,您可以进入货物。toml,并将其作为功能添加到<code>chrono。

[depenencies]
chrono = { version: "0.4.19", features = ["serde"] }

或者,chrono在其文档中列出了一些(但不是全部?)可选功能。但是,并非所有板条箱都这样做,文档有时可能会过时,因此我通常更喜欢手动方法

至于deserialize_with交互和枚举上未标记之间的问题,我没有看到你的代码有任何问题。这可能是 serde 中的一个错误,所以我建议您在 serde 存储库上创建一个问题,以便他们可以进一步研究发生此错误的原因。

闻人飞白
2023-03-14

@jonasbb帮助我意识到使用< code>[0,16.9," 2020-12-23 00:23:14"]时代码可以工作,但在尝试反序列化< code>["0 "," 16.9 "," 2020-12-23 00:23:14"]时却不行。默认情况下,Serde不序列化字符串中的数字,对I32和F64的尝试只是无声地失败。这将在本期serde-aux中讨论,可以使用非正式serde-aux机箱解决。

 类似资料:
  • 问题内容: 我有一些从Web服务返回的JSON数据。JSON是顶级数组: 使用make 可以对数组中包含的数据进行反序列化,但是,我无法让Serde对顶级数组进行反序列化。 我是否缺少某些内容,还是Serde不能对顶级数组进行反序列化? 问题答案: 您可以使用:

  • 问题内容: 我想使用自定义功能对a进行序列化和反序列化,但是Serde的书没有涵盖此功能,并且代码文档也无济于事。 我知道Serde可以很容易地反序列化,因为Chrono支持Serde, 但是 我想学习Serde,所以我想自己实现。当我运行此代码时,出现错误: 问题答案: 结构反序列化的默认行为是,当字段不以序列化形式出现时,为其分配各自的默认值。请注意,这与container 属性 不同,con

  • 问题内容: 我如何使用gson 2.2.4序列化和反序列化一个简单的枚举? 问题答案: 根据 GsonAPI文档 ,Gson提供了的默认序列化/反序列化,因此基本上,应使用标准和方法(与其他类型一样)对序列化和反序列化。

  • 我正在尝试使用Spring Cloud Stream框架构建一个简单的Kafka Streams应用程序。我可以连接到流以推送原始数据进行处理。但是当我尝试按键处理流进行事件计数时,我得到了未找到的运行应用程序时异常。我检查了我的项目包含的库,我可以找到类,它没有丢失。我不确定为什么在运行时它没有被加载! 下面是我的源文件。 <代码>com。pgp。学Kafka。分析。分析应用程序 <代码>com

  • 我想序列化/反序列化具有可变行长度和内容的CSV文件,如下所示: /test.csv 在我看来,最简单的表示方法是下面的< code>enum: Cargo.toml 运行以下命令 梅因 指纹 使用和,是否有简单的解决方案?我觉得我遗漏了一两个<code>serde</code>属性,但在文档中还没有找到正确的属性。 编辑 Netwave建议添加属性。序列化现在可以工作了,反序列化会出现以下错误:

  • 问题内容: 我正在使用JAVA 1.6和Jackson 1.9.9我有一个枚举 我添加了一个@JsonValue,这似乎可以将对象序列化为: 但是当我尝试反序列化时,我得到了 我在这里想念什么? 问题答案: 如果你希望将枚举类与其JSON表示完全脱钩,则@xbakesx指出的序列化器/反序列化器解决方案是一个很好的解决方案。 另外,如果你喜欢一个独立的解决方案,则基于·和·注释的实现会更方便。 因