Что такое Serde и зачем она нужна
Serde (сокращение от Serialization/Deserialization) — это фреймворк для сериализации и десериализации структур данных на языке Rust. Она является стандартом де-факто для работы с форматами данных в экосистеме Rust. Библиотека позволяет преобразовывать сложные типы Rust (структуры, перечисления, векторы, хеш-таблицы) в различные текстовые и бинарные форматы (JSON, YAML, TOML, BSON, MessagePack, CBOR, и многие другие) и обратно.
Основная философия Serde — производительность без компромиссов. Она использует мощную систему макросов Rust для генерации высокооптимизированного кода на этапе компиляции, что делает её одной из самых быстрых библиотек сериализации среди всех языков программирования. Serde не привязана к какому-либо конкретному формату: она предоставляет абстрактные трейты Serialize и Deserialize, а конкретные форматы реализуются в отдельных крейтах (например, serde_json, serde_yaml).
Зачем нужна Serde?
- Сохранение состояния: запись конфигураций, игровых сохранений, кэша на диск
- Сетевые протоколы: обмен данными между клиентом и сервером (REST API, WebSocket)
- Конфигурационные файлы: чтение настроек из JSON/YAML/TOML
- Базы данных: сериализация записей для хранения в Redis, MongoDB и других БД
- Межпроцессное взаимодействие: передача данных между процессами через pipe или сокеты
Установка
Serde устанавливается через менеджер пакетов Cargo, встроенный в Rust. Для начала работы добавьте зависимости в файл Cargo.toml:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Объяснение зависимостей:
serde— ядро библиотеки с трейтамиSerializeиDeserialize. Флагfeatures = ["derive"]включает поддержку макроса#[derive(Serialize, Deserialize)].serde_json— реализация формата JSON. Аналогично подключаютсяserde_yaml,serde_toml,bincodeи другие.
Если вы работаете с Rust 2021 edition или новее, достаточно просто добавить эти строки. Для установки конкретной версии укажите номер, например serde_json = "1.0.128".
Быстрый старт: первый пример
Создадим простую структуру и сериализуем её в JSON, а затем десериализуем обратно:
use serde::{Deserialize, Serialize};
use serde_json;
// Структура с автоматической генерацией кода сериализации/десериализации
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
email: String,
active: bool,
}
fn main() {
// Создаём экземпляр структуры
let user = User {
id: 42,
name: "Алиса".to_string(),
email: "alice@example.com".to_string(),
active: true,
};
// Сериализация в строку JSON
let json_string = serde_json::to_string(&user).unwrap();
println!("Сериализованный JSON: {}", json_string);
// Десериализация обратно в структуру
let deserialized_user: User = serde_json::from_str(&json_string).unwrap();
println!("Десериализованная структура: {:?}", deserialized_user);
// Проверяем, что данные не потерялись
assert_eq!(user.id, deserialized_user.id);
assert_eq!(user.name, deserialized_user.name);
}
Вывод программы:
Сериализованный JSON: {"id":42,"name":"Алиса","email":"alice@example.com","active":true}
Десериализованная структура: User { id: 42, name: "Алиса", email: "alice@example.com", active: true }
Как видите, достаточно добавить #[derive(Serialize, Deserialize)] над структурой, и Serde автоматически генерирует всю необходимую логику. Это магия процедурных макросов Rust.
Основные методы и функции Serde
Рассмотрим ключевые функции, предоставляемые Serde и её адаптерами форматов. Все примеры используют serde_json как наиболее популярный формат, но методы универсальны.
1. serde_json::to_string
Что делает: Сериализует переданное значение в строку JSON. Это самый простой способ получить текстовое представление данных.
Параметры:
value: &T— ссылка на значение, реализующее трейтSerialize
Возвращает: Result<String, Error> — строку JSON или ошибку сериализации.
Пример:
use serde_json;
let data = vec!["apple", "banana", "cherry"];
let json = serde_json::to_string(&data).unwrap();
// Результат: ["apple","banana","cherry"]
2. serde_json::from_str
Что делает: Десериализует строку JSON в указанный тип Rust. Тип возвращаемого значения должен быть указан явно или выведен компилятором.
Параметры:
s: &str— строка, содержащая JSON
Возвращает: Result<T, Error> — десериализованное значение или ошибку.
Пример:
use serde_json;
use std::collections::HashMap;
let json_str = r#"{"name":"Rust","year":2015}"#;
let map: HashMap<String, serde_json::Value> = serde_json::from_str(json_str).unwrap();
println!("{:?}", map); // {"name": "Rust", "year": 2015}
3. serde_json::to_value
Что делает: Преобразует любое сериализуемое значение в универсальный тип serde_json::Value, который может хранить любую JSON-структуру (объект, массив, строку, число, булево значение, null).
Параметры:
value: &T— ссылка на сериализуемое значение
Возвращает: Result<Value, Error>
Пример:
use serde_json::{self, Value};
let number = 42;
let value: Value = serde_json::to_value(&number).unwrap();
assert_eq!(value, Value::Number(42.into()));
let text = "hello";
let value: Value = serde_json::to_value(&text).unwrap();
assert_eq!(value, Value::String("hello".to_string()));
4. serde_json::from_value
Что делает: Обратная операция к to_value — преобразует Value обратно в конкретный тип Rust.
Параметры:
value: Value— значение JSON (забирает владение)
Возвращает: Result<T, Error>
Пример:
use serde_json::{self, Value};
let json_value: Value = serde_json::from_str(r#"{"x": 10, "y": 20}"#).unwrap();
let point: (i32, i32) = serde_json::from_value(json_value).unwrap();
assert_eq!(point, (10, 20));
5. serde_json::to_writer
Что делает: Сериализует данные напрямую в поток (например, файл или буфер), что эффективнее, чем сначала получать строку.
Параметры:
writer: W— любой тип, реализующийstd::io::Write(файл, Vec<u8>, буфер)value: &T— сериализуемое значение
Возвращает: Result<(), Error>
Пример:
use serde_json;
use std::fs::File;
let data = vec![1, 2, 3, 4, 5];
let file = File::create("numbers.json").unwrap();
serde_json::to_writer(file, &data).unwrap();
6. serde_json::from_reader
Что делает: Десериализует данные из потока (файла, сетевого сокета, буфера). Полезно для работы с большими объёмами данных, которые не помещаются в память целиком.
Параметры:
reader: R— любой тип, реализующийstd::io::Read
Возвращает: Result<T, Error>
Пример:
use serde_json;
use std::fs::File;
let file = File::open("config.json").unwrap();
let config: serde_json::Value = serde_json::from_reader(file).unwrap();
println!("Прочитана конфигурация: {:?}", config);
7. serde::Serialize::serialize
Что делает: Основной метод трейта Serialize. Вызывается автоматически при использовании функций выше, но может быть реализован вручную для кастомной логики сериализации.
Параметры:
&self— ссылка на сериализуемое значениеserializer: S— сериализатор (реализует трейтSerializer)
Возвращает: Result<S::Ok, S::Error>
Пример (ручная реализация):
use serde::{Serialize, Serializer};
struct Point {
x: i32,
y: i32,
}
impl Serialize for Point {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("Point", 2)?;
state.serialize_field("x", &self.x)?;
state.serialize_field("y", &self.y)?;
state.end()
}
}
8. serde::Deserialize::deserialize
Что делает: Основной метод трейта Deserialize. Аналогично serialize, может быть реализован вручную для нестандартных форматов или валидации.
Параметры:
deserializer: D— десериализатор
Возвращает: Result<Self, D::Error>
Пример (ручная реализация):
use serde::{Deserialize, Deserializer};
impl<'de> Deserialize<'de> for Point {
fn deserialize<D