如何使用Serde使用自定义函数反序列化可选字段?

时间:2022-09-27 20:51:24

I want to serialize and deserialize a chrono::NaiveDate with custom functions, but the Serde book does not cover this functionality and the code docs also do not help.

我想使用自定义函数序列化和反序列化chrono :: NaiveDate,但Serde书籍不包含此功能,代码文档也没有帮助。

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate chrono;

use chrono::NaiveDate;


mod date_serde {
    use chrono::NaiveDate;
    use serde::{self, Deserialize, Serializer, Deserializer};

    pub fn serialize<S>(date: &Option<NaiveDate>, s: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        if let Some(ref d) = *date {
            return s.serialize_str(&d.format("%Y-%m-%d").to_string())
        }
        s.serialize_none()
    }

    pub fn deserialize<'de, D>(deserializer: D)
        -> Result<Option<NaiveDate>, D::Error>
        where D: Deserializer<'de> {
        let s: Option<String> = Option::deserialize(deserializer)?;
        if let Some(s) = s {
            return Ok(Some(NaiveDate::parse_from_str(&s, "%Y-%m-%d").map_err(serde::de::Error::custom)?))
        }

        Ok(None)
    }
}

#[derive(Debug, Serialize, Deserialize)]
struct Test {
    pub i: u64,
    #[serde(with = "date_serde")]
    pub date: Option<NaiveDate>,
}

fn main() {
    let mut test: Test = serde_json::from_str(r#"{"i": 3, "date": "2015-02-03"}"#).unwrap();
    assert_eq!(test.i, 3);
    assert_eq!(test.date, Some(NaiveDate::from_ymd(2015, 02, 03)));
    test = serde_json::from_str(r#"{"i": 5}"#).unwrap();
    assert_eq!(test.i, 5);
    assert_eq!(test.date, None);
}

I know that Option<chrono::NaiveDate> can be easily deserialized by Serde because Chrono has Serde support, but I'm trying to learn Serde so I want to implement it myself. When I run this code I have a error:

我知道Option 可以很容易地被Serde反序列化,因为Chrono有Serde支持,但我正在尝试学习Serde所以我想自己实现它。当我运行此代码时,我有一个错误:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ErrorImpl { code: Message("missing field `date`"), line: 1, column: 8 }', /checkout/src/libcore/result.rs:859
note: Run with `RUST_BACKTRACE=1` for a backtrace.

1 个解决方案

#1


3  

A field of type Option here does not tell the deserializer that the field may not exist. Rather, it suggests that it contains a field with empty or null content (none in Serde terms). In serde_json for instance, Option<String> is the JavaScript equivalent to "either null or string" (null | string in TypeScript / Flow notation). This code below works fine:

此处类型为Option的字段不会告诉解串器该字段可能不存在。相反,它表明它包含一个空或空内容的字段(Serde术语中没有)。例如,在serde_json中,Option 是等效于“null或string”的JavaScript(TypeScript / Flow表示法中为null | string)。以下代码工作正常:

let test: Test = serde_json::from_str(r#"{"i": 5, "date": null}"#).unwrap();
assert_eq!(test.i, 5);
assert_eq!(test.date, None);

Luckily, the deserialization process can become more permissive just by adding the serde(default) attribute (Option::default yields None):

幸运的是,通过添加serde(默认)属性(Option :: default yield None),反序列化过程可以变得更加宽松:

#[derive(Debug, Serialize, Deserialize)]
struct Test {
    pub i: u64,

    #[serde(default)]
    #[serde(with = "date_serde")]
    pub date: Option<NaiveDate>,
}

Playground

操场

See also How to deserialize a JSON file which contains null values using Serde? (not a duplicate, but contains a similar and pertinent use case)

另请参见如何使用Serde反序列化包含空值的JSON文件? (不是重复,但包含类似且相关的用例)

#1


3  

A field of type Option here does not tell the deserializer that the field may not exist. Rather, it suggests that it contains a field with empty or null content (none in Serde terms). In serde_json for instance, Option<String> is the JavaScript equivalent to "either null or string" (null | string in TypeScript / Flow notation). This code below works fine:

此处类型为Option的字段不会告诉解串器该字段可能不存在。相反,它表明它包含一个空或空内容的字段(Serde术语中没有)。例如,在serde_json中,Option 是等效于“null或string”的JavaScript(TypeScript / Flow表示法中为null | string)。以下代码工作正常:

let test: Test = serde_json::from_str(r#"{"i": 5, "date": null}"#).unwrap();
assert_eq!(test.i, 5);
assert_eq!(test.date, None);

Luckily, the deserialization process can become more permissive just by adding the serde(default) attribute (Option::default yields None):

幸运的是,通过添加serde(默认)属性(Option :: default yield None),反序列化过程可以变得更加宽松:

#[derive(Debug, Serialize, Deserialize)]
struct Test {
    pub i: u64,

    #[serde(default)]
    #[serde(with = "date_serde")]
    pub date: Option<NaiveDate>,
}

Playground

操场

See also How to deserialize a JSON file which contains null values using Serde? (not a duplicate, but contains a similar and pertinent use case)

另请参见如何使用Serde反序列化包含空值的JSON文件? (不是重复,但包含类似且相关的用例)