Traitement JSON en Rust : guide complet avec serde_json
JSON (JavaScript Object Notation) est l'un des formats d'échange de données les plus populaires en développement web. En Rust, le traitement JSON est effectué à l'aide de la puissante bibliothèque serde_json, qui fait partie de l'écosystème Serde — un framework de sérialisation et désérialisation de structures de données. Dans cet article, nous allons détailler comment travailler avec JSON en Rust : de l'installation aux exemples complexes avec des structures imbriquées.
Installation et configuration
Pour commencer, ajoutez les dépendances dans le fichier Cargo.toml :
[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"La bibliothèque serde fournit les macros #[derive(Serialize, Deserialize)], et serde_json est responsable de la conversion des données en JSON et vice versa.
Sérialisation et désérialisation de base
Prenons un exemple simple : créons une structure User et apprenons à la convertir en JSON et inversement.
use serde::{Serialize, Deserialize};use serde_json;
#[derive(Debug, Serialize, Deserialize)]struct User { name: String, age: u8, email: String,}
fn main() { // Création d'une instance de la structure let user = User { name: "Алексей".to_string(), age: 30, email: "alex@example.com".to_string(), };
// Sérialisation en chaîne JSON let json_string = serde_json::to_string(&user).unwrap(); println!("JSON: {}", json_string);
// Désérialisation du JSON vers la structure let deserialized_user: User = serde_json::from_str(&json_string).unwrap(); println!("Désérialisé : {:?}", deserialized_user);}Résultat d'exécution :
JSON: {"name":"Алексей","age":30,"email":"alex@example.com"}Désérialisé : User { name: "Алексей", age: 30, email: "alex@example.com" }Travailler avec des structures imbriquées
Le JSON contient souvent des objets et des tableaux imbriqués. Rust permet de modéliser facilement ces structures :
#[derive(Debug, Serialize, Deserialize)]struct Address { city: String, street: String, house: u16,}
#[derive(Debug, Serialize, Deserialize)]struct Person { name: String, age: u8, address: Address, hobbies: Vec<String>,}
fn main() { let person = Person { name: "Мария".to_string(), age: 25, address: Address { city: "Москва".to_string(), street: "Тверская".to_string(), house: 10, }, hobbies: vec!["чтение".to_string(), "спорт".to_string()], };
// Affichage JSON formaté avec indentation let pretty_json = serde_json::to_string_pretty(&person).unwrap(); println!("{}", pretty_json);}Affichage :
{ "name": "Мария", "age": 25, "address": { "city": "Москва", "street": "Тверская", "house": 10 }, "hobbies": [ "чтение", "спорт" ]}Gestion des erreurs et des champs optionnels
Dans les projets réels, les données peuvent être incomplètes. Rust propose des moyens élégants pour gérer ces situations :
- Option<T> — pour les champs optionnels
- Result<T, E> — pour la gestion des erreurs de parsing
- Attributs Serde — pour configurer le comportement de sérialisation
use serde::{Serialize, Deserialize};use serde_json::Result;
#[derive(Debug, Serialize, Deserialize)]struct Product { name: String, price: f64, #[serde(default)] // Valeur par défaut si le champ est absent description: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] // Ignorer si None discount: