🦀 源码深度解读 | 基于 serde v1.0
2026.03.08
Serde 是 Rust 生态中用于序列化和反序列化数据的框架。
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct User {
name: String,
age: u32,
active: bool,
}
// 序列化
let user = User { name: "Alice".into(), age: 30, active: true };
let json = serde_json::to_string(&user)?; // {"name":"Alice","age":30,"active":true}
// 反序列化
let decoded: User = serde_json::from_str(&json)?;
编译期生成代码,无运行时开销
支持自定义序列化逻辑和格式
充分利用 Rust 类型系统保证安全
支持借用输入数据的反序列化
设计哲学:数据结构与数据格式完全解耦,一个 Serialize 实现可用于所有格式!
| 类别 | 类型 | Rust 示例 |
|---|---|---|
| 原始类型 (14) | bool, i8-i128, u8-u128, f32, f64, char | true, 42i32, 3.14f64, '🦀' |
| 字符串 | string | &str, String |
| 字节数组 | byte array | &[u8], Vec<u8> |
| Option | none, some | Option<T> |
| Unit | unit, unit_struct, unit_variant | (), struct Foo; |
| Newtype | newtype_struct, newtype_variant | struct Millimeters(u8); |
| 序列 | seq, tuple, tuple_struct, tuple_variant | Vec<T>, (A, B, C) |
| 映射 | map, struct, struct_variant | HashMap<K,V>, struct S { } |
pub trait Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer;
}
核心职责:将 Rust 数据结构转换为 Serializer 能理解的抽象操作序列。
pub trait Serializer: Sized {
type Ok;
type Error: Error;
// 原始类型
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error>;
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error>;
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error>;
// 复合类型
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error>;
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error>;
fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error>;
// ... 更多方法
}
struct Point { x: i32, y: i32 }
impl Serialize for Point {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
// 1. 开始序列化结构体
let mut s = serializer.serialize_struct("Point", 2)?;
// 2. 序列化字段
s.serialize_field("x", &self.x)?;
s.serialize_field("y", &self.y)?;
// 3. 结束
s.end()
}
}
JSON 输出:{"x":10,"y":20}
Bincode 输出:[10, 0, 0, 0, 20, 0, 0, 0](二进制)
pub trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
}
生命周期 'de:表示反序列化器可能借用的数据的生命周期,支持零拷贝反序列化。
pub trait Deserializer<'de>: Sized {
type Error: Error;
// 反序列化任何类型(用于自描述格式如 JSON)
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>;
// 特定类型提示(用于非自描述格式如 Postcard)
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>;
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>;
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>;
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where V: Visitor<'de>;
}
impl<'de> Deserialize<'de> for Point {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
// 1. 定义字段
enum Field { X, Y }
// 2. 定义 Visitor
struct PointVisitor;
impl<'de> Visitor<'de> for PointVisitor {
type Value = Point;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("struct Point")
}
fn visit_map<M>(self, mut map: M) -> Result<Point, M::Error>
where M: MapAccess<'de> {
let mut x = None;
let mut y = None;
while let Some(key) = map.next_key()? {
match key {
Field::X => { x = Some(map.next_value()?); }
Field::Y => { y = Some(map.next_value()?); }
}
}
Ok(Point { x: x.unwrap(), y: y.unwrap() })
}
}
// 3. 调用 deserializer
deserializer.deserialize_struct("Point", FIELDS, PointVisitor)
}
}
pub trait Visitor<'de>: Sized {
type Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
// 原始类型访问
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where E: Error { ... }
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where E: Error { ... }
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: Error { ... }
// 复合类型访问
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where A: SeqAccess<'de> { ... }
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where A: MapAccess<'de> { ... }
}
设计模式:Visitor 是经典的访问者模式,Deserializer 遍历数据并调用 Visitor 的相应方法。
// 输入
#[derive(Serialize, Deserialize)]
struct User {
name: String,
age: u32,
}
// 生成的代码(简化版)
impl Serialize for User {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let mut __serde_state = serializer.serialize_struct("User", 2)?;
SerializeStruct::serialize_field(&mut __serde_state, "name", &self.name)?;
SerializeStruct::serialize_field(&mut __serde_state, "age", &self.age)?;
SerializeStruct::end(__serde_state)
}
}
编译期生成:所有代码在编译时生成,零运行时开销!
源码路径:serde_derive/src/ser.rs
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
let ctxt = Ctxt::new();
let cont = Container::from_ast(&ctxt, input, Derive::Serialize, &private.ident());
let ident = &cont.ident;
let params = Parameters::new(&cont);
let body = serialize_body(&cont, ¶ms);
quote! {
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
fn serialize<__S>(&self, __serializer: __S) -> _serde::Result<__S::Ok, __S::Error>
where __S: _serde::Serializer {
#body
}
}
}
}
源码路径:serde_derive/src/de.rs
pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
let ctxt = Ctxt::new();
let cont = Container::from_ast(&ctxt, input, Derive::Deserialize, &private.ident());
let params = Parameters::new(&cont);
let body = deserialize_body(&cont, ¶ms);
let delife = params.borrowed.de_lifetime();
quote! {
impl #de_impl_generics _serde::Deserialize<#delife>
for #ident #ty_generics #where_clause {
fn deserialize<__D>(__deserializer: __D) -> _serde::Result<Self, __D::Error>
where __D: _serde::Deserializer<#delife> {
#body
}
}
}
}
pub trait Error: Sized + StdError {
fn custom<T>(msg: T) -> Self where T: Display;
fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self;
fn invalid_value(unexp: Unexpected, exp: &dyn Expected) -> Self;
fn invalid_length(len: usize, exp: &dyn Expected) -> Self;
fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self;
fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self;
fn missing_field(field: &'static str) -> Self;
fn duplicate_field(field: &'static str) -> Self;
}
pub enum Unexpected<'a> {
Bool(bool),
Unsigned(u64),
Signed(i64),
Float(f64),
Str(&'a str),
Bytes(&'a [u8]),
Unit, Option, Seq, Map, Enum, ...
}
// 零拷贝反序列化
#[derive(Deserialize)]
struct BorrowedData<'a> {
// 借用输入字符串,无需分配新内存
name: &'a str,
bytes: &'a [u8],
}
// 反序列化时数据借用自输入
let input = r#"{"name":"hello","bytes":[1,2,3]}"#;
let data: BorrowedData = serde_json::from_str(input)?;
// data.name 直接指向 input 中的 "hello"
性能提升:零拷贝可避免大量内存分配,特别适合大数据量场景。
{"name":"test"}// 普通反序列化 - 需要分配
struct Owned {
name: String, // 分配新内存存储 "test"
}
// 零拷贝反序列化 - 直接借用
struct Borrowed<'a> {
name: &'a str, // 指向原始输入中的 "test"
}
// serde_json 内部处理
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
// v 是从输入字符串切片得到的引用
Ok(Borrowed { name: v })
}
// 字段重命名
#[derive(Serialize, Deserialize)]
struct User {
#[serde(rename = "fullName")]
full_name: String,
#[serde(rename = "createdAt")]
created_at: DateTime,
}
// 批量重命名规则
#[serde(rename_all = "camelCase")]
struct ApiRequest {
user_id: String, // → userId
created_at: i64, // → createdAt
}
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
enum Status {
InProgress, // → IN_PROGRESS
Completed, // → COMPLETED
}
支持的重命名规则:lowercase, UPPECASE, PascalCase, camelCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case, SCREAMING-KEBAB-CASE
#[derive(Serialize, Deserialize)]
struct User {
name: String,
// 序列化时跳过
#[serde(skip_serializing)]
password: String,
// 反序列化时跳过
#[serde(skip_deserializing)]
internal_id: u64,
// 两者都跳过
#[serde(skip)]
cache: HashMap<String, String>,
// 条件跳过
#[serde(skip_serializing_if = "Option::is_none")]
optional_field: Option<String>,
}
#[derive(Deserialize)]
struct Config {
// 使用 Default trait
#[serde(default)]
port: u16, // 默认 0
// 自定义默认值函数
#[serde(default = "default_host")]
host: String,
// 嵌套结构默认值
#[serde(default)]
options: Options,
}
fn default_host() -> String {
"localhost".to_string()
}
// 整个结构体使用默认值
#[serde(default)]
struct Settings {
timeout: u64,
retries: u32,
}
// 使用 with 属性
#[derive(Serialize, Deserialize)]
struct Event {
#[serde(with = "my_datetime_format")]
timestamp: DateTime,
}
mod my_datetime_format {
use serde::{Serialize, Deserialize, Serializer, Deserializer};
pub fn serialize<S>(date: &DateTime, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
serializer.serialize_str(&date.to_rfc3339())
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime, D::Error>
where D: Deserializer<'de> {
let s = String::deserialize(deserializer)?;
DateTime::parse_from_rfc3339(&s)
.map_err(serde::de::Error::custom)
}
}
#[derive(Serialize, Deserialize)]
struct Pagination {
page: u32,
per_page: u32,
}
#[derive(Serialize, Deserialize)]
struct ApiResponse {
data: Vec<Item>,
// 将 Pagination 字段展开到顶层
#[serde(flatten)]
pagination: Pagination,
}
// 输出: {"data":[...], "page":1, "per_page":10}
// 而不是: {"data":[...], "pagination":{"page":1, "per_page":10}}
用途:组合多个结构体、处理额外字段、实现 trait 对象序列化。
enum Message {
Request { id: String, method: String },
Response { id: String, result: Value },
}
// 默认外部标签格式
{"Request": {"id": "1", "method": "get"}}
// 内部标签
#[serde(tag = "type")]
enum Message {
Request { id: String, method: String },
// → {"type": "Request", "id": "1", "method": "get"}
}
// 相邻标签
#[serde(tag = "type", content = "data")]
enum Message {
Request { id: String, method: String },
// → {"type": "Request", "data": {"id": "1", "method": "get"}}
}
// 无标签
#[serde(untagged)]
enum Value {
String(String),
Number(i64),
// → 直接输出值,无类型标签
}
| 策略 | 属性 | JSON 示例 |
|---|---|---|
| 外部标签 | (默认) | {"Variant":{...}} |
| 内部标签 | tag="type" | {"type":"Variant",...} |
| 相邻标签 | tag+content | {"type":"V","data":{...}} |
| 无标签 | untagged | {...} 或 "value" |
无标签风险:untagged 可能导致歧义,反序列化时按顺序尝试匹配。
enum Value {
Null,
Bool(bool),
Number(Number),
String(String),
Array(Vec<Value>),
Object(Map<String, Value>),
}
// 动态解析 JSON
let v: Value = serde_json::from_str(r#"{"name":"test"}"#)?;
println!("{}", v["name"]); // test
// 构建复杂 JSON
let json = json!({
"name": "Alice",
"age": 30,
"hobbies": ["reading", "coding"],
"address": {
"city": "Beijing"
}
});
// 1. 使用零拷贝
#[derive(Deserialize)]
struct FastData<'a> {
#[serde(borrow)]
data: &'a [u8],
}
// 2. 预分配缓冲区
let mut buffer = Vec::with_capacity(1024);
serde_json::to_writer(&mut buffer, &data)?;
// 3. 使用 from_reader 避免加载全部数据
let data: BigStruct = serde_json::from_reader(file)?;
// 4. 二进制格式更快
let bytes = bincode::serialize(&data)?; // 比 JSON 快 3-5 倍
// 5. 跳过不需要的字段
#[derive(Deserialize)]
struct Partial {
#[serde(flatten)]
extra: IgnoredAny, // 忽略所有额外字段
}
| 操作 | serde_json | bincode | postcard |
|---|---|---|---|
| 序列化 1MB 数据 | 2.5ms | 0.8ms | 0.5ms |
| 反序列化 1MB 数据 | 3.2ms | 1.0ms | 0.7ms |
| 输出大小 | 100% | ~40% | ~35% |
结论:二进制格式在速度和大小上都优于文本格式,但 JSON 更通用。
struct SimpleSerializer;
impl Serializer for SimpleSerializer {
type Ok = String;
type Error = Error;
type SerializeSeq = Impossible<String, Error>;
// ...
fn serialize_bool(self, v: bool) -> Result<String, Error> {
Ok(if v { "true".into() } else { "false".into() })
}
fn serialize_i32(self, v: i32) -> Result<String, Error> {
Ok(v.to_string())
}
fn serialize_str(self, value: &str) -> Result<String, Error> {
Ok(format!("\"{}\"", value))
}
}
// 使用
let output = 42.serialize(SimpleSerializer)?; // "42"
struct SimpleDeserializer<'a> {
input: &'a str,
}
impl<'de> Deserializer<'de> for SimpleDeserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
where V: Visitor<'de> {
if self.input.starts_with('"') {
visitor.visit_str(self.input.trim_matches('"'))
} else if let Ok(n) = self.input.parse::<i64>() {
visitor.visit_i64(n)
} else {
Err(Error::custom("unknown type"))
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ApiResponse<T> {
success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
data: Option<T>,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<ApiError>,
#[serde(with = "ts_milliseconds")]
timestamp: DateTime<Utc>,
}
#[derive(Serialize, Deserialize)]
struct ApiError {
code: u32,
message: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
details: Vec<String>,
}
#[derive(Serialize, Deserialize)]
#[repr(u8)]
enum PacketType {
Handshake = 0x01,
Data = 0x02,
Ack = 0x03,
}
#[derive(Serialize, Deserialize)]
struct Packet {
#[serde(rename = "type")]
type_: PacketType,
#[serde(with = "BigEndian")]
length: u32,
#[serde(skip_serializing_if = "Vec::is_empty")]
payload: Vec<u8>,
}
// 使用 bincode 序列化
let packet = Packet { type_: PacketType::Data, length: 100, payload: vec![...] };
let bytes = bincode::serialize(&packet)?;
// 为第三方类型实现 Serde
#[serde(remote = "DateTime")]
impl DateTimeSerde {
#[serde(getter = "DateTime::timestamp")]
fn timestamp(dt: &DateTime) -> i64 { dt.timestamp() }
#[serde(getter = "DateTime::timestamp_millis")]
fn timestamp_millis(dt: &DateTime) -> i64 { dt.timestamp_millis() }
}
#[derive(Deserialize)]
struct Event {
#[serde(with = "DateTimeSerde")]
created_at: DateTime,
}
#[derive(Serialize, Deserialize)]
struct Container<T> {
value: T,
metadata: String,
}
// 自动生成正确的 trait bounds
// 等价于:
impl<T: Serialize> Serialize for Container<T> { ... }
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Container<T> { ... }
// 自定义 bounds
#[serde(bound = "T: Serialize + Clone")]
struct StrictContainer<T> {
value: T,
}
// ❌ 陷阱 1:忽略生命周期
struct Bad<'a> {
data: &'a str,
}
let json = r#"{"data":"test"}"#.to_string(); // 移动!
let v: Bad = serde_json::from_str(&json)?; // 编译错误
// ✅ 解决方案:使用 Cow 或 owned
#[derive(Deserialize)]
struct Good<'a> {
#[serde(borrow)]
data: Cow<'a, str>,
}
// ❌ 陷阱 2:未处理未知字段
// 默认会报错
// ✅ 解决方案
#[serde(deny_unknown_fields)] // 显式拒绝
struct Strict { ... }
#[serde(flatten)] // 忽略额外字段
extra: IgnoredAny,
// 1. 打印序列化结果
println!("{}", serde_json::to_string_pretty(&data)?);
// 2. 使用 #[serde(deny_unknown_fields)] 定位字段名问题
// 3. 自定义错误消息
#[serde(deny_unknown_fields, expecting = "a valid User object")]
struct User { ... }
// 4. 使用 serde_plain 调试
let s = serde_plain::to_string(&value)?;
// 5. 启用调试日志
RUST_LOG=serde=debug cargo run
// 6. 检查派生展开
cargo expand
| 特性 | Serde | protobuf | cap'n proto |
|---|---|---|---|
| Schema 要求 | ❌ 不需要 | ✅ 需要 | ✅ 需要 |
| 零拷贝 | ✅ 支持 | ❌ | ✅ 原生 |
| 格式灵活性 | ✅ 30+ | ❌ 仅 protobuf | ❌ 仅 cap'n |
| Rust 优先 | ✅ | ❌ | ❌ |
| 跨语言 | ⚠️ 有限 | ✅ | ✅ |
🦀 访问 serde.rs 了解更多