常用生态库 intermediate 30 分钟 更新 2026-06-15

serde:序列化与反序列化

用 serde 和 serde_json 在结构体与 JSON 之间转换。

serde:序列化与反序列化

你会学到什么

  • serde 是 Rust 事实标准的序列化框架。
  • 给结构体派生 Serialize / Deserialize 即可与 JSON 互转。
  • serde_json 提供 to_stringfrom_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"