Сериализация объектов в Rust: serde, bincode, JSON и YAML

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Сериализация объектов в Rust: полное руководство по библиотеке serde и форматам данных

Сериализация — это процесс преобразования структур данных или объектов в формат, который можно сохранить в файл, передать по сети или закэшировать. В языке Rust эта задача решается элегантно и эффективно с помощью библиотеки serde (Serialization/Deserialization). В этой статье мы подробно разберём, как работает сериализация в Rust, какие форматы данных поддерживаются, и как выбрать подходящий инструмент для вашего проекта.

Что такое serde и почему это стандарт де-факто?

serde — это фреймворк для сериализации и десериализации структур данных в Rust. Он не привязан к конкретному формату — вы можете использовать JSON, Bincode, YAML, TOML, MessagePack, CBOR и многие другие. Основная идея: вы описываете свою структуру один раз, а serde автоматически генерирует код для работы с любым форматом через систему трейтов Serialize и Deserialize.

Преимущества serde:

  • Максимальная производительность — код генерируется на этапе компиляции (zero-cost abstraction)
  • Безопасность типов — ошибки несоответствия форматов ловятся на этапе компиляции
  • Поддержка сложных структур: enum, векторы, хэш-карты, вложенные объекты
  • Возможность кастомизации через атрибуты

Установка и базовая настройка

Добавьте в Cargo.toml следующие зависимости:

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

Ключевой момент — feature "derive" для serde. Без неё вам придётся вручную реализовывать трейты Serialize и Deserialize.

Простой пример: сериализация в JSON

JSON — самый популярный формат для веб-приложений и API. Рассмотрим базовый пример:

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
    is_active: bool,
}

fn main() {
    let user = User {
        id: 42,
        name: "Алексей".to_string(),
        email: "alex@example.com".to_string(),
        is_active: true,
    };

    // Сериализация в JSON
    let json = serde_json::to_string(&user).unwrap();
    println!("JSON: {}", json);

    // Десериализация из JSON
    let deserialized: User = serde_json::from_str(&json).unwrap();
    println!("Десериализовано: {:?}", deserialized);
}

Вывод:

JSON: {"id":42,"name":"Алексей","email":"alex@example.com","is_active":true}
Десериализовано: User { id: 42, name: "Алексей", email: "alex@example.com", is_active: true }

Бинарная сериализация с bincode

Для высокопроизводительных приложений (игры, системы реального времени, базы данных) часто требуется компактный бинарный формат. bincode — один из лучших вариантов:

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct GameState {
    level: u16,
    health: f32,
    inventory: Vec<String>,
    checkpoint: (f64, f64),
}

fn main() {
    let state = GameState {
        level: 5,
        health: 87.5,
        inventory: vec!["меч".into(), "зелье".into()],
        checkpoint: (120.5, -34.8),
    };

    // Сериализация в бинарный формат
    let binary = bincode::serialize(&state).unwrap();
    println!("Бинарный размер: {} байт", binary.len());

    // Десериализация
    let restored: GameState = bincode::deserialize(&binary).unwrap();
    println!("Восстановлено: {:?}", restored);
}

Bincode даёт выигрыш в размере данных и скорости обработки по сравнению с JSON. Например, структура из 4 полей займёт около 40 байт против 100+ в JSON.

Работа с YAML и TOML

Для конфигурационных файлов часто используют YAML или TOML. Подключите соответствующие крейты:

[dependencies]
serde_yaml = "0.9"
toml = "0.7"

Пример сериализации в YAML:

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct Config {
    server: ServerConfig,
    database: DatabaseConfig,
}

#[derive(Debug, Serialize, Deserialize)]
struct ServerConfig {                    

Рекомендаций