提问人:VP. 提问时间:6/1/2017 最后编辑:ShepmasterVP. 更新时间:12/15/2018 访问量:35774
如何使用 Serde 使用自定义函数反序列化可选字段?
How can I deserialize an optional field with custom functions using Serde?
问:
我想使用自定义函数序列化和反序列化,但 Serde 书没有涵盖此功能,代码文档也无济于事。chrono::NaiveDate
#[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);
}
我知道它可以很容易地被 Serde 反序列化,因为 Chrono 支持 Serde,但我正在尝试学习 Serde,所以我想自己实现它。当我运行此代码时,我有一个错误:Option<chrono::NaiveDate>
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.
答:
65赞
E_net4
6/1/2017
#1
结构反序列化的默认行为是,当字段不以序列化形式存在时,为字段分配各自的默认值。请注意,这与容器 #[serde(default)]
属性不同,后者使用结构的默认值填充字段。
#[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”)])
时,此规则会发生变化。此处的字段类型不再告诉反序列化程序该字段可能不存在。相反,它表明存在一个可能为空或空内容的字段(在 Serde 术语中)。例如,JavaScript 是否等同于“either or”(在 TypeScript / Flow 表示法中)。下面的代码适用于给定的定义和日期反序列化程序:Option
none
serde_json
Option<String>
null
string
null | string
let test: Test = serde_json::from_str(r#"{"i": 5, "date": null}"#)?;
assert_eq!(test.i, 5);
assert_eq!(test.date, None);
幸运的是,只需添加属性( yields ):serde(default)
Option::default
None
#[derive(Debug, Serialize, Deserialize)]
struct Test {
pub i: u64,
#[serde(default)]
#[serde(with = "date_serde")]
pub date: Option<NaiveDate>,
}
另请参阅:
评论