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.

#[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:

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.

推荐答案

struct 反序列化的默认行为是,当字段不以序列化形式存在时,用其各自的默认值分配字段.请注意,这与container #[serde(default)] attribute不同,后者用 struct 的默认值填充字段.

#[derive(Debug, PartialEq, Deserialize)]
pub struct Foo<'a> {
    x: Option<&'a str>,
}

let foo: Foo = serde_json::from_str("{}")?;
assert_eq!(foo, Foo { x: None });

然而,当我们使用另一个反序列化函数(#[serde(deserialize_with = "path")])时,这个规则会发生变化.这里Option类型的字段不再告诉反序列化程序该字段可能不存在.相反,它表明存在一个可能包含空或空内容的字段(Serde术语为none).例如,在serde_json中,Option<String>相当于"nullstring"(TypeScript/Flow notation中的null | string).下面的代码适用于给定的定义和日期反序列化器:

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

幸运的是,只需添加serde(default)属性(Option::default产生None),反序列化过程就可以变得更加宽松:

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

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

Playground

另请参阅:

Json相关问答推荐

当 JSON 字段名称有空格时,ABAP 中的 JSON 反序列化

遍历 JSON,检索父值

xidel:是否可以从 JSON 对象中检索特定的嵌套值?

如何加入或合并列表元素列表(未知长度)

如何在 Dart 中与多个 map (字典)相交

将嵌套的 JSON 对象规范化为 Pandas 数据框

android - 在 adb logcat 输出中格式化 json 字符串

如何使用 Newtonsoft.Json 包在 C#(4.0) 中解析我的 json 字符串?

PostgreSQL 中的 JSON 模式验证?

使用 JSON.Net 的 C# 到 JSON 序列化

Jackson JSON序列化,通过级别定义避免递归

使用适用于 Python 的 Google API - 我从哪里获取 client_secrets.json 文件?

JSON 和 BSON 哪个更轻量级?

在 .NET 中缩小缩进的 JSON 字符串

使用 JSON.NET 序列化/反序列化对象字典

将 Pandas 数据框转换为嵌套 JSON

如何解析 JSON 并将其值转换为数组?

在 Go 中解析 JSON 时如何指定默认值

如何处理基于 JSON 的 RESTful 代码中的异常?

类似字典的 JSON 模式