Rust 中的序列化是什么?

更新于 2026-01-17

什么是序列化?

序列化(Serialization)是指将一个 Python 对象(如列表、字典或类对象)转换为一种易于存储或共享的格式,例如文本文件、JSON 字符串或字节流。

你可以把序列化想象成将你的数据打包进一个盒子,这样你就可以通过互联网发送它、将其保存到文件中,或者存入数据库。

当你需要再次使用这些数据时,就打开这个盒子,这个过程称为反序列化(Deserialization)。

例如:

import json

# 原始 Python 对象(字典)
student = {
    "name": "Alice",
    "age": 21,
    "skills": ["Python", "Machine Learning", "Data Analysis"]
}

# 序列化:将字典转换为 JSON 字符串
serialized_data = json.dumps(student)
print("Serialized Data:", serialized_data)

# 反序列化:将 JSON 字符串转换回 Python 对象
deserialized_data = json.loads(serialized_data)
print("Deserialized Data:", deserialized_data)

输出:

Serialized Data: {"name": "Alice", "age": 21, "skills": ["Python", "Machine Learning", "Data Analysis"]}
Deserialized Data: {'name': 'Alice', 'age': 21, 'skills': ['Python', 'Machine Learning', 'Data Analysis']}

代码解释:

  • json.dumps() 将 Python 对象转换为 JSON 字符串(序列化)。
  • json.loads() 将 JSON 字符串转换回 Python 对象(反序列化)。

序列化的常见用途

序列化不仅仅是一个技术概念;它在现代软件开发中几乎无处不在。每当需要存储、共享或重用数据时,序列化都扮演着重要角色。

  1. 保存数据:序列化最常见的用途之一是将数据保存到文件中,以便将来再次使用。与其将所有内容保留在内存中(程序停止后就会消失),不如通过序列化将对象转换为可存储的格式(如 JSON、二进制或 XML)并保存到磁盘上。

  2. 数据传输:序列化对于在网络上传输数据也至关重要。计算机、服务器和 API 并不能直接理解像 Python 字典或 Java 对象这样的复杂数据结构。
    序列化通过将这些对象转换为标准格式(如 JSON、XML 或 Protobuf)来解决这个问题,使数据能够通过互联网传输。

  3. 数据互操作性:在当今的技术世界中,系统的不同部分通常使用不同的编程语言编写,或运行在不同的平台上。序列化通过使用通用的、与语言无关的格式,使得这些系统能够相互理解和交换数据。


Rust 中的序列化

在 Rust 中,序列化通过一个名为 Serde 的强大库变得非常简单。Serde 是 “Serialize/Deserialize”(序列化/反序列化)的缩写,它是将 Rust 数据结构转换为各种格式(如 JSON、TOML、YAML,甚至自定义二进制格式)并再转换回来的最广泛使用且最受信赖的解决方案。

在项目中设置 Serde

在开始使用 Serde 之前,你需要将其添加到你的项目中。这通过更新 Cargo.toml 文件完成,该文件用于管理 Rust 项目的依赖项。

步骤 1:添加 Serde 依赖项

打开你的 Cargo.toml 文件,并在 [dependencies] 部分下添加以下内容:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
  • serde 是提供序列化和反序列化所需 trait 和宏的核心库。
  • serde_json 是一个辅助 crate,让你可以轻松处理 JSON 格式,这是最常见的序列化格式之一。

运行以下命令以包含这些依赖项:

cargo build

这将确保 Serde 及其 JSON 支持已正确包含在你的项目中。


如何在 Rust 中进行序列化和反序列化

该过程主要分为两个步骤:

  • 序列化:将 Rust 结构体转换为 JSON 字符串(以便存储、发送或共享)。
  • 反序列化:将 JSON 字符串转换回 Rust 结构体(以便在代码中再次使用)。

1. 序列化为 JSON

序列化是将 Rust 结构体转换为 JSON 字符串的过程。

示例:将数据序列化为 JSON

use serde::Serialize;
use serde_json;

#[derive(Serialize)]
struct User {
    username: String,
    age: u8,
    email: String,
}

fn main() {
    // 创建一个结构体实例
    let user = User {
        username: String::from("Alice"),
        age: 30,
        email: String::from("alice@example.com"),
    };

    // 将其转换为 JSON 字符串
    let json_string = serde_json::to_string(&user).expect("Failed to convert to JSON");

    println!("Serialized JSON: {}", json_string);
}

输出:

Serialized JSON: {"username":"Alice","age":30,"email":"alice@example.com"}

解释:

  • #[derive(Serialize)] 告诉 Serde 这个结构体可以被序列化。
  • serde_json::to_string(&user) 将结构体转换为 JSON 字符串。

2. 从 JSON 反序列化

反序列化是将 JSON 字符串转换回 Rust 结构体的过程。

示例:从 JSON 反序列化数据

use serde::Deserialize;
use serde_json;

#[derive(Deserialize)]
struct User {
    username: String,
    age: u8,
    email: String,
}

fn main() {
    // 一个我们接收到的或从文件加载的 JSON 字符串
    let json_data = r#"{"username":"Alice","age":30,"email":"alice@example.com"}"#;

    // 将 JSON 转换回 Rust 结构体
    let user: User = serde_json::from_str(json_data).expect("Failed to parse JSON");

    println!("Name: {}", user.username);
    println!("Age: {}", user.age);
    println!("Email: {}", user.email);
}

输出:

Name: Alice
Age: 30
Email: alice@example.com

解释:

  • #[derive(Deserialize)] 允许从 JSON 创建该结构体。
  • serde_json::from_str(json_data) 将 JSON 字符串解析为 User 结构体。

3. 处理序列化和反序列化错误

在处理序列化和反序列化时,错误非常常见,尤其是在处理来自外部源(如文件、API 或用户输入)的数据时。

例如:

  • JSON 中的数据类型可能不正确。
  • 可能缺少必需字段。
  • 格式可能无效。

Rust 是一门注重安全的语言,因此不会静默忽略这些错误。相反,它强制你使用 Result 类型来处理它们,从而确保你的程序保持可靠,不会意外崩溃。

示例:错误处理

use serde_json;

fn main() {
    // 包含错误的 JSON 数据:"age" 是字符串而不是数字
    let invalid_json = r#"{"name": "Alice", "age": "thirty"}"#;

    // 尝试反序列化并处理任何错误
    match serde_json::from_str::<serde_json::Value>(invalid_json) {
        Ok(data) => {
            println!("Successfully deserialized data: {:?}", data);
        }
        Err(error) => {
            println!("Failed to deserialize JSON: {}", error);
        }
    }
}

输出:

Failed to deserialize JSON: invalid type: string "thirty", expected a number at line 1 column 30

4. 使用其他格式(TOML)

序列化不仅限于 JSON;Rust 的 serde 库还支持许多其他数据格式,如 TOML、YAML 和二进制格式。

要在 Rust 中使用 TOML,你需要在项目中包含 toml crate。

Cargo.toml 中添加以下内容:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"

示例:序列化和反序列化 TOML

下面是一个简单示例,我们将 Rust 结构体转换为 TOML,然后再转换回结构体:

use serde::{Serialize, Deserialize};
use toml;

#[derive(Serialize, Deserialize, Debug)]
struct Settings {
    project: String,
    version: String,
    debug_mode: bool,
}

fn main() {
    // 步骤 1:创建一个结构体实例
    let settings = Settings {
        project: String::from("RustApp"),
        version: String::from("2.5.1"),
        debug_mode: true,
    };

    // 步骤 2:将结构体序列化为 TOML 字符串
    let toml_string = toml::to_string(&settings).expect("Failed to serialize data");
    println!("Serialized TOML:\n{}", toml_string);

    // 步骤 3:将 TOML 字符串反序列化回结构体
    let parsed: Settings = toml::from_str(&toml_string).expect("Failed to deserialize TOML");
    println!(
        "Parsed Data -> Project: {}, Version: {}, Debug Mode: {}",
        parsed.project, parsed.version, parsed.debug_mode
    );
}

输出:

Serialized TOML:
project = "RustApp"
version = "2.5.1"
debug_mode = true

Parsed Data -> Project: RustApp, Version: 2.5.1, Debug Mode: true

5. 二进制序列化

我们已经使用了像 JSON 和 TOML 这样的基于文本的格式,它们易于阅读但占用更多空间。在许多实际应用中(如保存游戏数据、缓存或通过网络发送数据),你希望使用更快、更紧凑的格式,这就是为什么我们要使用二进制序列化

二进制序列化将你的数据结构转换为字节序列,而不是人类可读的文本。这使得它更小、处理速度更快,并且在存储或传输方面更高效。

在项目中添加 bincode

要启用二进制序列化,请在 Cargo.toml 中包含 bincode crate:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3"

示例:二进制序列化

use serde::{Serialize, Deserialize};
use bincode;

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    // 步骤 1:创建一个结构体实例
    let point = Point { x: 42, y: 58 };

    // 步骤 2:将结构体序列化为二进制格式
    let binary = bincode::serialize(&point).expect("Failed to serialize to binary");
    println!("Serialized Binary Data: {:?}", binary);

    // 步骤 3:将二进制数据反序列化回 Rust 结构体
    let decoded_point: Point = bincode::deserialize(&binary).expect("Failed to deserialize binary");
    println!("Deserialized Point: {:?}", decoded_point);
}

输出:

Serialized Binary Data: [2, 0, 0, 0, 58, 0, 0, 0]
Deserialized Point: Point { x: 42, y: 58 }