rust - 如何为计时时间戳使用自定义 serde 反序列化器?
问题描述
我正在尝试将 JSON 解析为具有chrono::DateTime
字段的结构。JSON 以自定义格式保存时间戳,我为此编写了反序列化程序。
如何连接两者并使用它来工作#[serde(deserialize_with)]
?
我正在使用NaiveDateTime
更简单的代码
extern crate serde;
extern crate serde_json;
use serde::Deserialize;
extern crate chrono;
use chrono::NaiveDateTime;
fn from_timestamp(time: &String) -> NaiveDateTime {
NaiveDateTime::parse_from_str(time, "%Y-%m-%dT%H:%M:%S.%f").unwrap()
}
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "from_timestamp")]
timestamp: NaiveDateTime,
}
fn main() {
let result: MyJson =
serde_json::from_str(r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108"}"#)
.unwrap();
println!("{:?}", result);
}
我收到三个不同的编译错误:
error[E0308]: mismatched types
--> src/main.rs:11:10
|
11 | #[derive(Deserialize, Debug)]
| ^^^^^^^^^^^ expected reference, found type parameter
|
= note: expected type `&std::string::String`
found type `__D`
error[E0308]: mismatched types
--> src/main.rs:11:10
|
11 | #[derive(Deserialize, Debug)]
| ^^^^^^^^^^-
| | |
| | this match expression has type `chrono::NaiveDateTime`
| expected struct `chrono::NaiveDateTime`, found enum `std::result::Result`
| in this macro invocation
|
= note: expected type `chrono::NaiveDateTime`
found type `std::result::Result<_, _>`
error[E0308]: mismatched types
--> src/main.rs:11:10
|
11 | #[derive(Deserialize, Debug)]
| ^^^^^^^^^^-
| | |
| | this match expression has type `chrono::NaiveDateTime`
| expected struct `chrono::NaiveDateTime`, found enum `std::result::Result`
| in this macro invocation
|
= note: expected type `chrono::NaiveDateTime`
found type `std::result::Result<_, _>`
我很确定该from_timestamp
函数返回的是DateTime
struct 而不是 a Result
,所以我不知道“预期的 struct chrono::NaiveDateTime
,找到的 enum std::result::Result
”可能意味着什么。
解决方案
虽然@edwardw 的回答在技术上是正确的,但恕我直言包含太多样板文件。
NaiveDataTime
实现FromStr
,这意味着您可以编写可重用的通用反序列化器函数。
一个令人费解的示例 - 确实在 JSON 中添加了表示为字符串的age
字段 ( )。u8
只是为了证明您可以将它用于任何实现FromStr
.
use std::fmt::Display;
use std::str::FromStr;
use chrono::NaiveDateTime;
use serde::{de, Deserialize, Deserializer};
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "deserialize_from_str")]
timestamp: NaiveDateTime,
#[serde(deserialize_with = "deserialize_from_str")]
age: u8,
}
// You can use this deserializer for any type that implements FromStr
// and the FromStr::Err implements Display
fn deserialize_from_str<'de, S, D>(deserializer: D) -> Result<S, D::Error>
where
S: FromStr, // Required for S::from_str...
S::Err: Display, // Required for .map_err(de::Error::custom)
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
S::from_str(&s).map_err(de::Error::custom)
}
fn main() {
let result: MyJson = serde_json::from_str(
r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108", "age": "11"}"#,
)
.unwrap();
println!("{:?}", result);
}
如果您想指定格式(使用NaiveDateTime::parse_from_str
),那就更容易了:
use chrono::NaiveDateTime;
use serde::{de, Deserialize, Deserializer};
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "naive_date_time_from_str")]
timestamp: NaiveDateTime,
}
fn naive_date_time_from_str<'de, D>(deserializer: D) -> Result<NaiveDateTime, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S.%f").map_err(de::Error::custom)
}
fn main() {
let result: MyJson =
serde_json::from_str(r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108"}"#)
.unwrap();
println!("{:?}", result);
}
#[serde(deserialize_with = "path")]
文档:
使用与其实现不同的函数反序列化此字段
Deserialize
。给定的函数必须是可调用的fn<'de, D>(D) -> Result<T, D::Error> where D: Deserializer<'de>
,尽管它也可以是泛型的T
。使用的字段deserialize_with
不需要实现Deserialize
。
推荐阅读
- excel - 4个条件4个答案的Excel语句
- javascript - 如何将mysql的数据行转换为javascript数组?Node.js 应用程序
- javascript - 将 CSS 和 JS 定位到特定表
- html - 如何将标签更改为与另一个页面上使用的类似标签不同?
- python - django.core.exceptions.ImproperlyConfigured:mysqlclient 1.3.13 在 MySQL DB 中启动 Django
- c# - Unity、Scene 和 ScriptableObject
- mpeg-dash - MPD文件中参数SegmentTimeline的作用是什么?
- scala.js - 带有 ScalaJS 的 PlotlyJS:3D 图形/WebGL 的问题
- data-structures - 重组树的数据结构:父母是排列
- javascript - TypeError [ERR_INVALID_ARG_TYPE]:“原始”参数必须是函数类型。接收类型未定义