Serde 元编程:从过程宏到零成本抽象

从编译期元编程视角剖析 Serde 的工程实现。

几乎每一个 Rust 项目都依赖 Serde。它的使用极其朴素——写一行 #[derive(Serialize, Deserialize)],任何数据结构就能在 JSON、YAML、TOML、Bincode、MessagePack 之间自由流转。但在这行轻量语法背后,隐藏着 Rust 生态最精巧的工程设计之一:一套由过程宏、trait、泛型和单态化共同构建的零成本抽象

本专栏不教读者"怎么用 Serde"。本专栏拆解 Serde 源码——从 syn 解析 AST、quote 生成 TokenStream,到 Data Model 如何把"M 种数据结构 × N 种格式"的组合爆炸降为 M+N 的实现复杂度;从 Serializer/Deserializer trait 的边界设计,到 Visitor 模式为什么是反序列化的唯一正解;从属性宏 #[serde(rename)] 的解析机制,到借用反序列化如何在编译期证明生命周期安全。

这是《Rust 源码之道》本系列的第四卷。读完本专栏,你不只学会了 Serde——你掌握了 Rust 过程宏这门"元能力"。再看 Axum 的 #[derive(FromRequest)]、sqlx 的 query!、clap 的 #[derive(Parser)]、tokio 的 #[tokio::main],你会发现它们共享同一套工程范式。

flowchart TB
  D["#[derive(Serialize, Deserialize)]"] --> PM
  subgraph PM [过程宏 · 编译期运行的 Rust 函数]
    direction LR
    TS[TokenStream] --> SYN[syn<br/>解析成 AST] --> ATTR["属性系统<br/>#[serde(...)]"]
    ATTR --> QT[quote<br/>生成代码]
  end
  QT --> CG["codegen<br/>serialize_body 五路分派"]
  CG --> IMPL[你的类型的 impl]
  IMPL --> DM
  subgraph DM [Data Model · 把 M×N 降成 M+N]
    direction LR
    SER["Serializer trait<br/>30 个方法 · self 是 move"] --- DE[Deserializer + Visitor]
  end
  DM --> FMT[JSON · YAML · TOML<br/>Bincode · MessagePack]

Serde 真正的设计眼光在中间那一格。 M 种数据结构 × N 种格式本来是组合爆炸,Data Model 把它降成 M+N —— 每个类型只需实现一次 Serialize,每个格式只需实现一次 Serializer。这个抽象值多少,看一眼 Rust 生态里格式库的数量就知道了。

读完你能做到什么

  1. 理解 Data Model 这个中间层。 29 种原语的划分依据、为什么它能把组合爆炸降维、边界在哪(第2章 Data Model)。
  2. 读懂两个核心 trait 的设计取舍。 Serializer 的 30 个方法怎么组织、self 为什么是 move 语义、默认实现的性能兜底;以及 Visitor 模式为什么是反序列化的唯一正解(第3章 Serializer第4章 Deserializer 与 Visitor)。
  3. 自己写一个 derive 宏。 宏的三种形态、过程宏的运行时机、syn 解析 AST、quote 的 quasi-quoting 与 #var 插值、ToTokens#(...)* 重复语法,然后动手写出第一个 derive(第5章 宏系统全景第6章 TokenStream第7章 syn第8章 quote第9章 第一个 derive)。
  4. 看懂 Serde 自己的代码生成。 derive 的整体架构、属性系统怎么解析、expand_derive_serialize 的全貌、serialize_body 的五路分派,以及各种 struct/enum 形态各自生成什么(第10章 derive 架构第11章 属性系统第12章 序列化 codegen第13章 反序列化 codegen)。
  5. 处理 enum 与借用这两个难点。 四种 enum 标签表示(externally / internally / adjacently / untagged)各自的取舍,以及借用反序列化如何在编译期证明生命周期安全(第14章 enum 标签第15章 借用反序列化)。
  6. 用好高级属性并读懂一个真实格式实现。 进阶属性组合,以及 serde_json 是怎么落地这套抽象的(第16章 高级属性第17章 serde_json第18章 设计哲学)。

适合谁读

前置阅读:本专栏假设读者已经能写 Rust 代码,理解 trait、泛型、生命周期的基本概念。如果对这些机制的编译期实现尚有疑问,建议先读《Rust 编译器》。本专栏不依赖 Tokio 相关知识,可独立阅读。

目录

第一部分:开篇

第二部分:Data Model 与 trait 抽象

第三部分:过程宏工程学

第四部分:serde_derive 源码剖析

第五部分:高阶主题

第六部分:生态与总结

源码版本

本专栏所有源码引用均基于以下版本(2026 年 4 月 20 日锁定):

Crate 版本 Git Commit
serde 1.0.228 fa7da4a93567ed347ad0735c28e439fca688ef26
serde_json 1.0.149 dc8003a88e7142529cf4a7429c4778af31dadf50
syn 2.0.117 e027fef2adcd6588fa8097c63dc916778d1aa11b
quote 1.0.45 ba07807af385afeff97a5e75186f7a92eb629a79
proc-macro2 1.0.107 ed8a5497669cd63db33bf24646f261b012bbbc4a

读者可通过以下命令获取与本专栏完全一致的源码:

git clone https://github.com/serde-rs/serde.git
cd serde && git checkout fa7da4a

git clone https://github.com/serde-rs/json.git serde_json
cd serde_json && git checkout dc8003a

git clone https://github.com/dtolnay/syn.git
cd syn && git checkout e027fef

git clone https://github.com/dtolnay/quote.git
cd quote && git checkout ba07807

正文每一段源码引用都会标注文件路径和行号,读者可在对应版本的代码中逐行验证。

版权声明

本专栏内容为 杨艺韬 版权所有,保留一切权利。未经书面许可,不得全文或大段转载、改编、翻译,或用于任何商业用途(含以本专栏内容训练模型、生成衍生课程或商品)。

欢迎分享本专栏的链接。引用少量内容用于评论、教学或研究时,请署名 杨艺韬 并附上原文链接。