Serialización de objetos en Rust: guía completa sobre la librería serde y formatos de datos
La serialización es el proceso de convertir estructuras de datos u objetos en un formato que se pueda guardar en un archivo, transmitir por red o almacenar en caché. En el lenguaje Rust, esta tarea se resuelve de manera elegante y eficiente con la librería serde (Serialization/Deserialization). En este artículo, analizaremos en detalle cómo funciona la serialización en Rust, qué formatos de datos son compatibles y cómo elegir la herramienta adecuada para tu proyecto.
¿Qué es serde y por qué es el estándar de facto?
serde es un framework para la serialización y deserialización de estructuras de datos en Rust. No está vinculado a un formato específico: puedes usar JSON, Bincode, YAML, TOML, MessagePack, CBOR y muchos otros. La idea principal: describes tu estructura una vez, y serde genera automáticamente el código para trabajar con cualquier formato a través del sistema de traits Serialize y Deserialize.
Ventajas de serde:
- Máximo rendimiento: el código se genera en tiempo de compilación (zero-cost abstraction)
- Seguridad de tipos: los errores de discrepancia de formatos se detectan en tiempo de compilación
- Soporte para estructuras complejas: enum, vectores, mapas hash, objetos anidados
- Posibilidad de personalización mediante atributos
Instalación y configuración básica
Añade las siguientes dependencias a tu Cargo.toml:
[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"bincode = "1.3"El punto clave es la feature "derive" para serde. Sin ella, tendrías que implementar manualmente los traits Serialize y Deserialize.
Ejemplo sencillo: serialización a JSON
JSON es el formato más popular para aplicaciones web y API. Veamos un ejemplo básico:
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: "Alexéi".to_string(), email: "alex@example.com".to_string(), is_active: true, };
// Serialización a JSON let json = serde_json::to_string(&user).unwrap(); println!("JSON: {}", json);
// Deserialización desde JSON let deserialized: User = serde_json::from_str(&json).unwrap(); println!("Deserializado: {:?}", deserialized);}Salida:
JSON: {"id":42,"name":"Alexéi","email":"alex@example.com","is_active":true}Deserializado: User { id: 42, name: "Alexéi", email: "alex@example.com", is_active: true }Serialización binaria con bincode
Para aplicaciones de alto rendimiento (juegos, sistemas en tiempo real, bases de datos), a menudo se requiere un formato binario compacto. bincode es una de las mejores opciones:
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!["espada".into(), "poción".into()], checkpoint: (120.5, -34.8), };
// Serialización a formato binario let binary = bincode::serialize(&state).unwrap(); println!("Tamaño binario: {} bytes", binary.len());
// Deserialización let restored: GameState = bincode::deserialize(&binary).unwrap(); println!("Restaurado: {:?}", restored);}Bincode ofrece ventajas en tamaño de datos y velocidad de procesamiento en comparación con JSON. Por ejemplo, una estructura de 4 campos ocupará unos 40 bytes frente a más de 100 en JSON.
Trabajo con YAML y TOML
Para archivos de configuración