今天带大家学习一些serde的小技巧,让你在工作中如鱼得水,应付各种序列化问题,比如我们把first_name使用#[serde(rename_all = "camelCase")]序列化成firstName,也可以跳过某些字段不被序列化,也可以丢弃数据,自定义格式显示日期。
将字母下划线命名字段序列化成驼峰命名规则
#[derive[Serialize]]
#[serde(rename_all = "cameCase")]
struct Users{
user_name:String,
user_age:i32,
user_email:String
}
fn main(){
let user = Users{
user_name:"job".to_string(),
user_age:12,
user_email:"2859200@qq.com"
}
let josn = serde_json::to_string_pretty(&user).unwrap();
println!("{}",json);
}
跳过序列化字段
⚠️使用 skip_serializing 不会跳过 反序列化字段。如果只添加 skip_serializing 属性,然后尝试反序列化数据,会失败,因为仍会尝试反序列化已跳过的字段。请使用 skip 属性来同时跳过序列化和反序列化(参见字段属性: skip)。同样,使用 skip_deserializing 来仅跳过反序列化。
use serde::Serialize;
use std::collections::BTreeMap as Map;
#[derive(Serialize)]
struct Resource {
// 总是被序列化。
name: String,
// 从不被序列化。
#[serde(skip_serializing)]
hash: String,
// 使用方法来决定是否跳过该字段。
#[serde(skip_serializing_if = "Map::is_empty")]
metadata: Map<String, String>,
}
fn main() {
let resources = vec![
Resource {
name: "Stack Overflow".to_string(),
hash: "b6469c3f31653d281bbbfa6f94d60fea130abe38".to_string(),
metadata: Map::new(),
},
Resource {
name: "GitHub".to_string(),
hash: "5cb7a0c47e53854cd00e1a968de5abce1c124601".to_string(),
metadata: {
let mut metadata = Map::new();
metadata.insert("headquarters".to_string(),
"San Francisco".to_string());
metadata
},
},
];
let json = serde_json::to_string_pretty(&resources).unwrap();
// 打印:
//
// [
// {
// "name": "Stack Overflow"
// },
// {
// "name": "GitHub",
// "metadata": {
// "headquarters": "San Francisco"
// }
// }
// ]
println!("{}", json);
}
丢弃数据
use std::fmt;
use std::marker::PhantomData;
use serde::de::{
self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqAccess,
IgnoredAny,
};
use serde_json::json;
// 可用于仅反序列化序列中的第 `n` 个元素,并且可以高效地丢弃索引 `n` 之前或之后的任意类型元素的种子。
//
// 例如,仅反序列化索引为 3 的元素:
//
// NthElement::new(3).deserialize(deserializer)
pub struct NthElement<T> {
n: usize,
marker: PhantomData<fn() -> T>,
}
impl<T> NthElement<T> {
pub fn new(n: usize) -> Self {
NthElement {
n: n,
marker: PhantomData,
}
}
}
impl<'de, T> Visitor<'de> for NthElement<T>
where
T: Deserialize<'de>,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "我们关心索引 {} 处的序列", self.n)
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
// 跳过前 `n` 个元素。
for i in 0..self.n {
// 如果在到达元素 `n` 之前序列结束,则出错。
if seq.next_element::<IgnoredAny>()?.is_none() {
return Err(de::Error::invalid_length(i, &self));
}
}
// 反序列化我们关心的那个元素。
let nth = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(self.n, &self))?;
// 跳过 `n` 之后序列中的任何剩余元素。
while let Some(IgnoredAny) = seq.next_element()? {
// ignore
}
Ok(nth)
}
}
impl<'de, T> DeserializeSeed<'de> for NthElement<T>
where
T: Deserialize<'de>,
{
type Value = T;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(self)
}
}
fn main() {
let array = json!(["a", "b", "c", "d", "e"]);
let nth: String = NthElement::new(3).deserialize(&array).unwrap();
println!("{}", nth);
assert_eq!(nth, array[3]);
}
自定义格式显示日期
use chrono::{DateTime, Utc};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct StructWithCustomDate {
// DateTime 可以直接支持 Serde,但使用 RFC3339 格式。提供一些自定义逻辑使其使用我们想要的格式。
#[serde(with = "my_date_format")]
pub timestamp: DateTime<Utc>,
// 结构体中的其他字段。
pub bidder: String,
}
mod my_date_format {
use chrono::{DateTime, Utc, NaiveDateTime};
use serde::{self, Deserialize, Serializer, Deserializer};
const FORMAT: &'static str = "%Y-%m-%d %H:%M:%S";
// serialize_with 函数的签名必须遵循以下模式:
//
// fn serialize<S>(&T, S) -> Result<S::Ok, S::Error>
// where
// S: Serializer
//
// 尽管也可以对输入类型 T 进行泛型化。
pub fn serialize<S>(
date: &DateTime<Utc>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = format!("{}", date.format(FORMAT));
serializer.serialize_str(&s)
}
// deserialize_with 函数的签名必须遵循以下模式:
//
// fn deserialize<'de, D>(D) -> Result<T, D::Error>
// where
// D: Deserializer<'de>
//
// 尽管也可以对输出类型 T 进行泛型化。
pub fn deserialize<'de, D>(
deserializer: D,
) -> Result<DateTime<Utc>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let dt = NaiveDateTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom)?;
Ok(DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc))
}
}
fn main() {
let json_str = r#"
{
"timestamp": "2017-02-16 21:54:30",
"bidder": "Skrillex"
}
"#;
let data: StructWithCustomDate = serde_json::from_str(json_str).unwrap();
println!("{:#?}", data);
let serialized = serde_json::to_string_pretty(&data).unwrap();
println!("{}", serialized);
}
最后希望大家多多关注我的公众号:花说编程,此外加我微信更有rust学习资料赠送你