Serde:Rust数据序列化的事实标准,10593 Star
Serde:Rust数据序列化的事实标准,10593 Star
serde 在 GitHub 上拿到了 10,593 Star,是 Rust 生态里下载量最高的库之一。crates.io 上 serde 的总下载量超过 2 亿次,几乎所有用到数据交换的 Rust 项目都会直接或间接依赖它。Tokio、Actix-web、Diesel、wasm-bindgen 这些知名项目都在 Cargo.toml 里带着 serde。

Rust 标准库没有 JSON 解析,也没有 YAML 或 TOML 支持。这在很多语言里是标配功能,但 Rust 选择了把序列化这件事交给社区。Serde 填补了这个空缺,它提供一套框架而非一种实现:核心只定义 Serialize 和 Deserialize 两个 trait,具体的数据格式由独立子 crate 各司其职。这个分层设计让 Serde 本身不关心输出是 JSON 还是 BSON,格式 crate 也不用操心 Rust 类型系统里的生命周期和泛型约束。
1、解决了什么
Rust 的类型系统约束很多。每个 struct 字段都有明确的类型、生命周期、所有权标记。把一个 struct 转成 JSON 字符串再读回来,在 Python 或 JavaScript 里是内置函数调用,在 Rust 里则要靠序列化库把这些元信息翻译过去。
手写序列化逻辑本身不难,难的是每个结构体都要写。稍微大一点的系统里 struct 可能上百个,字段频繁变动,序列化代码和结构体定义脱节就是隐蔽的 bug。Serde 用派生宏把这件事压缩成一行标注:#[derive(Serialize, Deserialize)] 贴到 struct 上面,编译器在编译期展开代码,生成的实现和手写代码效率一致,没有运行时开销。枚举、Option、Vec、HashMap、嵌套结构、泛型结构体,全部自动覆盖,一行 glue code 都不用写。如果不想依赖派生宏,Serde 还提供了手写 impl 的路径,给特殊场景留了后门。
2、怎么用
Cargo.toml 加两行:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
struct 打上派生宏,序列化反序列化各一行调用:
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 1, y: 2 };
let json = serde_json::to_string(&point).unwrap();
// {"x":1,"y":2}
let back: Point = serde_json::from_str(&json).unwrap();
关键在于序列化方法和数据格式是分离的。同一份 struct 定义不用改,把 serde_json::to_string 换成 serde_yaml::to_string 就出 YAML,换成 toml::to_string 就出 TOML。换格式不换定义,这是 Serde 分层设计的直接体现。
3、格式生态
Serde 核心只有 trait。格式实现在各自的 crate 里:
serde_json(JSON)、serde_yaml(YAML)、toml(TOML)、bson(BSON)、rmp-serde(MessagePack)、avro-rs(Avro)、serde-pickle(Python Pickle 格式)、serde-xml-rs(XML)、csv(CSV)、serde_qs(URL 查询参数)、ron(Rust Object Notation)。社区还维护了 Hjson、JSON5、FlexBuffers 等格式的适配层。
这种架构的收益是单向的:要接入一种新格式,只需实现 Serializer 和 Deserializer 这两个 trait。所有已有的 struct 自动获得新格式支持,业务代码不动。反过来说,新增一个 struct 时,所有已支持的格式自动覆盖这个 struct。
4、真实场景的容错
线上的数据不会按文档来。字段名大小写不一致、多了未定义字段、数字写成字符串、“N/A” 之类占位符、null 需要解释成默认值。Serde 的属性宏用声明式的方式覆盖了这些场景:
#[derive(Deserialize)]
struct Config {
#[serde(rename = "PORT")]
port: u16, // 接收端字段名映射
#[serde(default)]
timeout_ms: u64, // 缺字段时填默认值
#[serde(alias = "hostname")]
host: String, // 同时识别多个字段名
#[serde(deny_unknown_fields)]
strict: bool, // 拒绝未定义字段
#[serde(deserialize_with = "from_str")]
count: u32, // 自定义反序列化函数
}
配合 #[serde(flatten)] 可以把嵌套 JSON 展开到当前 struct,#[serde(skip)] 跳过不需要持久化的字段,#[serde(rename_all = "camelCase")] 一键统一命名风格。全在属性层声明,struct 字段定义本身不改变。
5、适合谁
- 用 Rust 写 Web 服务,每天处理 JSON 请求和响应的后端开发。Serde 基本是 Rust Web 框架的默认序列化层
- 写 CLI 工具、需要加载 TOML 或 YAML 配置文件。clap 这类命令行解析库都内置了 Serde 集成
- 对接多种输出格式的系统,比如 HTTP API 返回 JSON 同时 MongoDB 存 BSON,或 gRPC 用 Protobuf 而日志用 JSON
- 做数据管道或消息队列,序列化中间结果用于跨进程或跨服务通信
- 游戏开发(Rust 生态),解析关卡数据、物品配置表
Serde 在 Rust 里的地位接近 Python 的 json 标准库加 Java 的 Jackson 之和。它不绑定任何格式,但几乎所有 Rust 格式库都绑定了它。

Jackson 之和。它不绑定任何格式,但几乎所有 Rust 格式库都绑定了它。
[外链图片转存中…(img-qS965VSu-1780489238851)]
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)