Rust 序列化库 Serde 完全指南:从入门到实战
序列化是贯穿开发的高频场景,比如网络通信的数据传输、配置文件的读写、数据持久化存储、跨服务接口的交互等。Serde 凭借高效、通用、灵活的特性,成为了绝大多数 Rust 项目的首选,甚至已然成为 Rust 生态中事实上的序列化标准库。
为什么 Serde 能成为 Rust 生态事实上的序列化标准
Rust 的核心设计理念之一是“零成本抽象”,Serde 严格遵循这一原则,与其他编程语言的序列化库不同,Serde 通过 Rust 的宏机制在编译期为数据结构自动生成序列化与反序列化代码,既保证了性能,又避免了手动编写重复代码的繁琐。这种非反射、编译期宏展开的机制,让 Serde 在序列化速度上表现非常突出,尤其是在高频序列化的场景,这也是大多数 Rust 项目优先选择 Serde 的核心原因。
除了零成本抽象,Serde 另一个核心设计是“解耦”,将数据结构的序列化能力与具体的序列化格式分离。任何数据只要实现了 Serialize(序列化)和 Deserialize(反序列化)这两个核心 trait,都能被 Serde 处理,无需额外的配置。而且社区提供丰富格式适配器库,如 serde_json、serde_yaml、toml、bincode 等,要进行相应格式的序列化与反序列化也非常方便。
也正因为以上两大核心原因,Serde 已成为 Rust 生态中事实上的序列化标准库,大量 Rust 生态库均集成了 Serde,如 Axum、Actix-web、Sqlx、Diesel 等。
快速上手 Serde
添加依赖
在 Cargo.toml 中添加 Serde 核心库及最常用的 JSON 格式适配器:
[dependencies]
# Serde 核心库,启用 derive 宏,自动生成 trait 实现
serde = { version = "1.0", features = ["derive"] }
# JSON 格式适配器
serde_json = "1.0"
通过 Serde 的 derive 特性,我们通过 Serialize, Deserialize 这两个派生宏,自动为数据结构实现序列化与反序列化的 trait,无需编写代码。
示例代码
Serde 自动支持 Rust 标准库中的大部分类型,如 u32、String、Vec、HashMap、Option 等,无需额外实现 trait,这极大的降低了使用门槛。对于无法不支持的数据类型,我们在高级应用章节会讲解如何处理。
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
// 为结构体添加序列化/反序列化能力,Debug 用于打印
#[derive(Serialize, Deserialize, Debug)]
// 使用驼峰命名,如将 is_active 转换为 isActive
#[serde(rename_all = "camelCase")]
struct User {
id: u32,
name: String,
email: Option<String>, // 可选字段,反序列化时缺失则为 None
#[serde(default)] // 缺失字段默认填充使用该类型默认值(bool 默认为 false)
is_active: bool,
tags: Vec<String>,
metadata: HashMap<String, String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut metadata = HashMap::new();
metadata.insert("role".to_string(), "admin".to_string());
metadata.insert("version".to_string(), "1.0.0".to_string());
let user = User {
id: 1001,
name: "Alice".to_string(),
email: Some("alice@example.com".to_string()),
is_active: true,
tags: vec!["rust".to_string(), "serde".to_string()],
metadata,
};
// 序列化
let json_str = serde_json::to_string(&user)?;
println!("序列化结果: {}", json_str);
// 反序列化
let deserialized_user: User = serde_json::from_str(&json_str)?;
println!("反序列化结果: {:?}", deserialized_user);
Ok(())
}
在项目根目录执行 cargo run 可得到如下结果:
序列化结果: {"id":1001,"name":"Alice","email":"alice@example.com","isActive":true,"tags":["rust","serde"],"metadata":{"version":"1.0.0","role":"admin"}}
反序列化结果: User { id: 1001, name: "Alice", email: Some("alice@example.com"), is_active: true, tags: ["rust", "serde"], metadata: {"version": "1.0.0", "role": "admin"} }
进阶技巧:自定义序列化/反序列化
学会了上面的示例,基本就满足大部分的使用场景了。但是在实际开发中,经常遇到特殊需求,如日期格式转换、加密字段、枚举映射等,这时候就需要手动实现自定义逻辑。
场景一:自定义日期格式
在实际开发中,日期通常需要转为指定格式(如 YYYY-MM-DD HH:MM:SS),而 Rust 标准库的 SystemTime 或第三方库 chrono 的日期类型,默认序列化格式不符合需求,需手动实现序列化/反序列化。
首先,我们先添加上 chrono 依赖:
[dependencies]
chrono = { version = "0.4", features = ["serde"] }
示例代码如下所示:
use std::ops::Deref;
use chrono::{DateTime, Local, NaiveDateTime, TimeZone, offset::LocalResult};
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
// 自定义日期类型(封装 chrono::DateTime)
#[derive(Debug, Clone, Copy)]
struct CustomDateTime(DateTime<Local>);
// 实现 Serialize trait:转为 "YYYY-MM-DD HH:MM:SS" 格式
impl Serialize for CustomDateTime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// self.0 访问内部的 DateTime<Local>
let formatted = format!("{}", self.0.format("%Y-%m-%d %H:%M:%S"));
serializer.serialize_str(&formatted)
}
}
// 实现 Deserialize trait:从 "YYYY-MM-DD HH:MM:SS" 转为 CustomDateTime
impl<'de> Deserialize<'de> for CustomDateTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
// 解析为朴素时间 (NaiveDateTime)
let naive =
NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S").map_err(de::Error::custom)?;
// 将朴素时间转换为本地时间 (Local)
let dt_local = match Local.from_local_datetime(&naive) {
LocalResult::Single(dt) => dt,
_ => {
return Err(de::Error::custom(
"Invalid or ambiguous local datetime due to DST transition",
));
}
};
Ok(CustomDateTime(dt_local))
}
}
// 实现 Deref 使得使用 DateTime<Local> 像一样使用 CustomDateTime
impl Deref for CustomDateTime {
type Target = DateTime<Local>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// 使用自定义日期类型
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
register_time: CustomDateTime, // 使用自定义日期字段
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
id: 1002,
name: "Bob".to_string(),
register_time: CustomDateTime(Local::now()),
};
let json_str = serde_json::to_string(&user)?;
println!("序列化结果: {}", json_str);
// 反序列化
let deserialized_user: User = serde_json::from_str(&json_str)?;
println!("反序列化结果: {:?}", deserialized_user);
Ok(())
}
执行 cargo run 可得到如下结果:
序列化结果: {"id":1002,"name":"Bob","register_time":"2026-04-06 14:05:27"}
反序列化结果: User { id: 1002, name: "Bob", register_time: CustomDateTime(2026-04-06T14:05:27+08:00) }
场景二:加密字段处理
在开发过程中,需要对于手机号、密码等敏感字段在序列化时进行加密,在反序列化时进行解密,这里我们通过 serialize_with 和 deserialize_with 来指定自定义函数。
use serde::{Deserialize, Deserializer, Serialize, Serializer};
// 模拟加密/解密函数(实际项目中替换为 AES、RSA 等真实加密算法)
fn encrypt(s: &str) -> String {
s.chars().rev().collect() // 简单反转字符串模拟加密
}
fn decrypt(s: &str) -> String {
s.chars().rev().collect() // 反转字符串模拟解密
}
// 自定义序列化函数(加密字段)
fn serialize_encrypted<S>(phone: &str, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let encrypted_phone = encrypt(phone);
serializer.serialize_str(&encrypted_phone)
}
// 自定义反序列化函数(解密字段)
fn deserialize_encrypted<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let encrypted_phone: String = Deserialize::deserialize(deserializer)?;
let decrypted_phone = decrypt(&encrypted_phone);
Ok(decrypted_phone)
}
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
// 指定自定义序列化/反序列化函数
#[serde(
serialize_with = "serialize_encrypted",
deserialize_with = "deserialize_encrypted"
)]
phone: String, // 敏感字段,自动加密/解密
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
id: 1003,
name: "Charlie".to_string(),
phone: "13800138000".to_string(), // 原始未加密手机号
};
let json_str = serde_json::to_string(&user)?;
println!("序列化结果: {}", json_str);
// 反序列化
let deserialized_user: User = serde_json::from_str(&json_str)?;
println!("反序列化结果: {:?}", deserialized_user);
Ok(())
}
执行 cargo run 可得到如下结果:
序列化结果: {"id":1003,"name":"Charlie","phone":"00083100831"}
反序列化结果: User { id: 1003, name: "Charlie", phone: "13800138000" }
场景三:枚举的自定义序列化
Rust 枚举默认序列化格式为枚举名称或索引,实际开发中常需要将枚举序列化为指定字符串或数字,这时候可以通过手动实现 trait 或使用 Serde 属性实现。
use serde::{Deserialize, Deserializer, Serialize, Serializer};
// 方式一:使用 Serde 属性(简单场景首选)
#[derive(Serialize, Deserialize, Debug)]
enum Status {
#[serde(rename = "active")] // 序列化为 "active"
Active,
#[serde(rename = "inactive")] // 序列化为 "inactive"
Inactive,
#[serde(rename = "disabled")] // 序列化为 "disabled"
Disabled,
}
// 方式二:手动实现 Serialize/Deserialize trait
#[derive(Debug)]
enum Role {
Admin,
User,
Guest,
}
impl Serialize for Role {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// 将枚举序列化为对应的数字
let role_num = match self {
Role::Admin => 0,
Role::User => 1,
Role::Guest => 2,
};
serializer.serialize_u8(role_num)
}
}
impl<'de> Deserialize<'de> for Role {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let role_num: u8 = Deserialize::deserialize(deserializer)?;
// 从数字反序列化为枚举
let role = match role_num {
0 => Role::Admin,
1 => Role::User,
2 => Role::Guest,
_ => return Err(serde::de::Error::custom("无效的角色值")),
};
Ok(role)
}
}
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
status: Status,
role: Role,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User {
id: 1004,
name: "David".to_string(),
status: Status::Active,
role: Role::Admin,
};
let json_str = serde_json::to_string(&user)?;
println!("序列化结果: {}", json_str);
// 反序列化
let deserialized_user: User = serde_json::from_str(&json_str)?;
println!("反序列化结果: {:?}", deserialized_user);
Ok(())
}
执行 cargo run 可得到如下结果:
序列化结果: {"id":1004,"name":"David","status":"active","role":0}
反序列化结果: User { id: 1004, name: "David", status: Active, role: Admin }
场景四:跳过不必要的字段与自定义默认值
在开发过程中,部分字段(如内部备注、临时计算字段)不需要序列化,或者是反序列化时字段缺失需设置自定义默认值,可以通过 Serde 提供的属性快速实现。
use serde::Deserialize;
// 自定义默认值函数
fn default_page_size() -> u32 {
10 // 分页默认大小为 10
}
#[derive(Deserialize, Debug)]
struct PageQuery {
page: u32,
#[serde(default = "default_page_size")] // 自定义默认值
page_size: u32,
#[serde(skip)] // 跳过该字段,不参与序列化/反序列化
internal_note: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let json_str = r#"{"page": 1}"#;
// 反序列化
let deserialized_user: PageQuery = serde_json::from_str(&json_str)?;
println!("反序列化结果: {:?}", deserialized_user);
Ok(())
}
执行 cargo run 可得到如下结果:
反序列化结果: PageQuery { page: 1, page_size: 10, internal_note: "" }
总结
看完整篇文章,相信你也知道了 Serde 是兼顾性能与易用性的,四个进阶使用示例,光看示例代码就比较容易理解了,可以说,Serde 成为 Rust 生态中事实上的序列化标准库不是没有理由的,反而有那种“必然性”。