这个问题很相似怎么做我为我不拥有的类型实现了一个我不拥有的特征?
我使用文档中描述的机制为 Date 编写了一个序列化程序,我的模块包装了一个序列化函数
pub mod my_date_format {使用 chrono::{Date, NaiveDate, Utc};使用 serde::{self, Deserialize, Deserializer, Serializer};const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";pub fn serialize(日期:&Date,序列化器:S)->结果在哪里S:序列化器,{let s = format!("{}", date.format(SERIALIZE_FORMAT));serializer.serialize_str(&s)}pub fn deserialize(解串器:D)->结果<日期,D::错误>在哪里D:解串器de",{让 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();让日期:Date<Utc>= Date::from_utc(x, now.offset().clone());日期})}}然后我可以这样做:
struct MyStruct {#[serde(with = "my_date_format")]酒吧开始:日期,}
问题是如果我将序列化的东西包装在其他类型(它们本身是可序列化的)中,我会得到错误:
#[serde(with = "my_date_format")]发布日期:Vec//不会工作pub box_date:Box//不会工作...
如何在使用自己的序列化程序时获得提供的实现?
https://docs.serde.rs/serde/ser/index.html#implementations-of-serialize-provided-by-serde
解决方案使用 serde_as
宏来自 serde_with
crate.它的工作方式类似于带有属性的 serde,但也支持包装器和集合类型.
既然你已经有了一个与 serde 一起使用的模块,那么困难的部分已经完成了.您可以在 板条箱文档.您只需要为特征 SerializeAs
和 DeserializeAs
添加一个本地类型和两个样板实现即可使用您的自定义转换.
使用 chrono::{Date, NaiveDate, Utc};struct MyDateFormat;impl serde_with::SerializeAs对于 MyDateFormat {fn serialize_as(值:&Date,序列化器:S) ->结果在哪里S: serde::Serializer,{my_date_format::serialize(value, serializer)}}实现<'de>serde_with::DeserializeAs对于 MyDateFormat {fn deserialize_as(解串器:D)->结果<日期,D::错误>在哪里D: serde::Deserializer,{my_date_format::deserialize(deserializer)}}#[serde_with::serde_as]#[派生(序列化,反序列化,调试)]结构我的结构{#[serde_as(as = "MyDateFormat")]日期:日期,#[serde_as(as = "Vec")]日期:Vec")]opt_date:选项<Date<Utc>>,#[serde_as(as = "Box")]boxed_date: Box,}fn 主(){让 s = MyStruct {日期:UTC::now().date().into(),日期: std::iter::repeat(Utc::now().date().into()).take(4).collect(),opt_date: 一些(Utc::now().date().into()),boxed_date: Box::new(Utc::now().date().into()),};让 json = serde_json::to_string_pretty(&s).unwrap();println!("{}", json);}//这个模块是从问题中未修改的pub mod my_date_format {使用 chrono::{Date, NaiveDate, Utc};使用 serde::{self, Deserialize, Deserializer, Serializer};const SERIALIZE_FORMAT: &'static str = "%Y-%m-%d";pub fn serialize(日期:&Date,序列化器:S)->结果在哪里S:序列化器,{let s = format!("{}", date.format(SERIALIZE_FORMAT));serializer.serialize_str(&s)}pub fn deserialize(deserializer: D) ->结果<日期,D::错误>在哪里D:解串器de",{让 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();让日期:Date<Utc>= Date::from_utc(x, now.offset().clone());日期})}}
This question is similarHow do I implement a trait I don't own for a type I don't own?
I wrote a serializer for Date, using the mechanism described in the documentation with my module wrapping a serialize function
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
})
}
}
then I can do:
struct MyStruct {
#[serde(with = "my_date_format")]
pub start: Date<Utc>,
}
Problem is if I wrap the serialized thing in other types (which are serializable themselves) I get errors:
#[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...
How can I gain the implementations provided while using my own serializer?
https://docs.serde.rs/serde/ser/index.html#implementations-of-serialize-provided-by-serde
解决方案Instead of relying on wrapper types it is possible to achieve the same results with the serde_as
macro from the serde_with
crate.It works like the serde with attribute but also supports wrapper and collections types.
Since you already have a module to use with serde's with, the hard part is already done.You can find the details in the crate documentation.You only need to add a local type and two boilerplate implementations for the traits SerializeAs
and DeserializeAs
to use your custom transformations.
use chrono::{Date, NaiveDate, Utc};
struct MyDateFormat;
impl serde_with::SerializeAs<Date<Utc>> for MyDateFormat {
fn serialize_as<S>(value: &Date<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
my_date_format::serialize(value, serializer)
}
}
impl<'de> serde_with::DeserializeAs<'de, Date<Utc>> for MyDateFormat {
fn deserialize_as<D>(deserializer: D) -> Result<Date<Utc>, D::Error>
where
D: serde::Deserializer<'de>,
{
my_date_format::deserialize(deserializer)
}
}
#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct MyStruct {
#[serde_as(as = "MyDateFormat")]
date: Date<Utc>,
#[serde_as(as = "Vec<MyDateFormat>")]
dates: Vec<Date<Utc>>,
#[serde_as(as = "Option<MyDateFormat>")]
opt_date: Option<Date<Utc>>,
#[serde_as(as = "Box<MyDateFormat>")]
boxed_date: Box<Date<Utc>>,
}
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);
}
// This module is taken uunmodified from the question
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
})
}
}
这篇关于如何为我不拥有的类型实现 serde 并让它支持复合/wrapper/collection 类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!