serde:序列化与反序列化
你会学到什么
serde是 Rust 事实标准的序列化框架。- 给结构体派生
Serialize/Deserialize即可与 JSON 互转。 serde_json提供to_string和from_str。
最小示例
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Task {
id: u32,
title: String,
done: bool,
}
运行代码
cd examples
cargo run -p rt_34_serde
cargo test -p rt_34_serde
依赖:
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
代码讲解
#[derive(Serialize, Deserialize)] 让编译器为类型生成转换代码,之后:
let json = serde_json::to_string(&task)?; // 结构体 -> JSON
let task: Task = serde_json::from_str(&json)?; // JSON -> 结构体
serde 是“数据格式无关”的:同一套派生既能配 JSON,也能配 YAML、TOML、MessagePack 等,只要换对应的 crate。
用 #[serde(rename = "...")]、#[serde(default)] 等属性可以微调字段名和默认值。
常见错误
忘了开启 derive 特性:
serde = "1" # ❌ 没有 features = ["derive"],#[derive(Serialize)] 不可用
练习
- 给
Task加一个tags: Vec<String>字段并序列化。 - 用
#[serde(rename = "is_done")]改变 JSON 里的字段名。
小结
serde 用派生宏把繁琐的序列化代码自动化,serde_json 是最常用的搭档。
下一步
错误处理也有趁手的库。下一章学习 anyhow 与 thiserror。
完整示例代码
下面是 examples/34_serde/ 的完整源码。无需 clone 仓库,直接在页面上阅读、复制、对照运行。
examples/34_serde/src/main.rs
//! serde + serde_json:结构体与 JSON 互转。
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Task {
id: u32,
title: String,
done: bool,
}
fn to_json(task: &Task) -> serde_json::Result<String> {
serde_json::to_string(task)
}
fn from_json(text: &str) -> serde_json::Result<Task> {
serde_json::from_str(text)
}
fn main() {
let task = Task {
id: 1,
title: "学习 serde".to_string(),
done: false,
};
let json = to_json(&task).expect("序列化失败");
println!("json = {json}");
let parsed = from_json(&json).expect("反序列化失败");
println!("parsed = {parsed:?}");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serializes_to_json() {
let task = Task {
id: 1,
title: "t".to_string(),
done: true,
};
assert_eq!(
to_json(&task).unwrap(),
r#"{"id":1,"title":"t","done":true}"#
);
}
#[test]
fn round_trips() {
let task = Task {
id: 9,
title: "round".to_string(),
done: false,
};
let json = to_json(&task).unwrap();
assert_eq!(from_json(&json).unwrap(), task);
}
#[test]
fn rejects_invalid_json() {
assert!(from_json("not json").is_err());
}
} examples/34_serde/Cargo.toml
[package]
name = "rt_34_serde"
version.workspace = true
edition.workspace = true
publish.workspace = true
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"