gpt4 book ai didi

rust - 如何为我不拥有的类型实现 serde 并让它支持复合/wrapper/collection 类型

转载 作者:行者123 更新时间:2023-12-03 11:41:30 24 4
gpt4 key购买 nike

这个问题类似
How do I implement a trait I don't own for a type I don't own?
我为 Date 编写了一个序列化程序,使用文档中描述的机制,我的模块包装了一个序列化函数


pub mod my_date_format {
use chrono::{Date, NaiveDate, Utc};
use serde::{self, Deserialize, Deserializer, Serializer};

const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";

pub fn serialize<S>(date: &Date<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = format!("{}", date.format(SERIALIZE_FORMAT));
serializer.serialize_str(&s)
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Date<Utc>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
NaiveDate::parse_from_str(s.as_str(), SERIALIZE_FORMAT)
.map_err(serde::de::Error::custom)
.map(|x| {
let now = Utc::now();
let date: Date<Utc> = Date::from_utc(x, now.offset().clone());
date
})
}
}
那么我可以这样做:
struct MyStruct {
#[serde(with = "my_date_format")]
pub start: Date<Utc>,
}
问题是如果我将序列化的东西包装在其他类型(它们本身是可序列化的)中,我会收到错误:
#[serde(with = "my_date_format")]
pub dates: Vec<Date<Utc> // this won't work now since my function doesn't serialize vectors
pub maybe_date: Option<Date<Utc>>> // won't work
pub box_date: Box<Date<Utc>> // won't work...
在使用我自己的序列化程序时如何获得提供的实现?
https://docs.serde.rs/serde/ser/index.html#implementations-of-serialize-provided-by-serde

最佳答案

最直接的方法,是作为 question you linked谈论,即创建一个新类型,换行 Date<Utc> ,并实现 Serialize Deserialize 对于那种类型。

#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Debug)]
struct FormattedDate(Date<Utc>);

impl Serialize for FormattedDate {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// If you implement `Deref`, then you don't need to add `.0`
let s = format!("{}", self.0.format(SERIALIZE_FORMAT));
serializer.serialize_str(&s)
}
}

impl<'de> Deserialize<'de> for FormattedDate {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
NaiveDate::parse_from_str(s.as_str(), SERIALIZE_FORMAT)
.map_err(serde::de::Error::custom)
.map(|x| {
let now = Utc::now();
let date: Date<Utc> = Date::from_utc(x, now.offset().clone());
Self(date)
// or
// date.into()
})
}
}
为了让生活更轻松,您可以实现 Deref DerefMut 然后使用 FormattedDate透明地表现得好像您正在使用 Date<Utc>直接地。
use std::ops::{Deref, DerefMut};

impl Deref for FormattedDate {
type Target = Date<Utc>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for FormattedDate {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
同样你可以实现 From Into , 这样您就可以轻松地在 FormattedDate 之间转换和 Date<Utc> .
impl From<Date<Utc>> for FormattedDate {
fn from(date: Date<Utc>) -> Self {
Self(date)
}
}

impl Into<Date<Utc>> for FormattedDate {
fn into(self) -> Date<Utc> {
self.0
}
}
现在,您提供的所有示例都易于使用:
#[derive(Serialize, Deserialize, Debug)]
struct MyStruct {
date: FormattedDate,
dates: Vec<FormattedDate>,
opt_date: Option<FormattedDate>,
boxed_date: Box<FormattedDate>,
}

fn main() {
let s = MyStruct {
date: Utc::now().date().into(),
dates: std::iter::repeat(Utc::now().date().into()).take(4).collect(),
opt_date: Some(Utc::now().date().into()),
boxed_date: Box::new(Utc::now().date().into()),
};

let json = serde_json::to_string_pretty(&s).unwrap();
println!("{}", json);
}
哪个输出:
{
"date": "2020-12-13",
"dates": [
"2020-12-13",
"2020-12-13",
"2020-12-13",
"2020-12-13"
],
"opt_date": "2020-12-13",
"boxed_date": "2020-12-13"
}

关于rust - 如何为我不拥有的类型实现 serde 并让它支持复合/wrapper/collection 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65279642/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com