once_cell Rust : guide complet avec exemples

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Bibliothèque once_cell pour Rust : initialisation paresseuse et cellules uniques

Qu'est-ce que c'est et pourquoi l'utiliser ?

La bibliothèque once_cell est l'une des plus populaires et utiles de l'écosystème Rust. Elle est conçue pour implémenter le modèle de conception d'initialisation paresseuse (lazy initialization) et créer des cellules uniques (once cells). Elle propose deux types clés : OnceCell et Lazy, qui résolvent un problème fondamental : la création différée d'une valeur, initialisée une seule fois lors de son premier accès.

Pourquoi est-ce utile ? En Rust, comme dans tout autre langage, il arrive souvent que la création d'un objet soit une opération coûteuse (par exemple, lire un fichier de configuration, établir une connexion à une base de données, charger un dictionnaire volumineux). Si cet objet n'est pas nécessaire immédiatement au démarrage du programme, mais seulement dans certaines conditions, son initialisation peut être reportée. once_cell le fait de manière sûre et efficace, garantissant que l'initialisation a lieu exactement une fois, même en cas d'accès concurrent depuis plusieurs threads.

Avant l'arrivée de once_cell dans la bibliothèque standard de Rust (depuis la version 1.70.0 avec std::cell::OnceCell et std::sync::OnceLock), cette bibliothèque était le standard de facto pour l'initialisation paresseuse. Elle reste pertinente aujourd'hui grâce à sa maturité, son large éventail de fonctionnalités et sa rétrocompatibilité. La bibliothèque fournit non seulement des versions thread-safe (sync), mais aussi des versions mono-thread (unsync) des types, ce qui permet d'éviter les frais généraux de synchronisation là où ils ne sont pas nécessaires.

Installation

Pour utiliser once_cell, ajoutez-le aux dépendances de votre projet dans Cargo.toml :

[dependencies]
once_cell = "1.20"

Ou exécutez la commande :

cargo add once_cell

Ensuite, vous pouvez importer les types nécessaires :

use once_cell::sync::{OnceCell, Lazy};
// ou pour une utilisation mono-thread :
use once_cell::unsync::{OnceCell as UnsyncOnceCell, Lazy as UnsyncLazy};

Démarrage rapide

Un exemple minimal fonctionnel utilisant Lazy pour l'initialisation paresseuse d'une variable statique :

use once_cell::sync::Lazy;
use std::collections::HashMap;

// La variable statique sera initialisée uniquement lors du premier accès
static CONFIG: Lazy<HashMap<String, String>> = Lazy::new(|| {
    println!("Initialisation de la configuration...");
    let mut map = HashMap::new();
    map.insert("host".to_string(), "localhost".to_string());
    map.insert("port".to_string(), "8080".to_string());
    map
});

fn main() {
    // Premier accès — l'initialisation a lieu ici
    println!("Hôte : {}", CONFIG.get("host").unwrap());
    
    // Deuxième accès — PAS d'initialisation, la valeur mise en cache est utilisée
    println!("Port : {}", CONFIG.get("port").unwrap());
}

Sortie du programme :

Initialisation de la configuration...
Hôte : localhost
Port : 8080

Méthodes et fonctions principales

Examinons 8 méthodes et fonctions clés de la bibliothèque once_cell avec des exemples d'utilisation.

1. OnceCell::new()

Signature : pub const fn new() -> OnceCell<T>

Fonctionnement : Crée une nouvelle cellule vide qui ne contient pas encore de valeur.

use once_cell::sync::OnceCell;

let cell: OnceCell<i32> = OnceCell::new();
assert!(cell.get().is_none()); // La cellule est vide

2. OnceCell::set()

Signature : pub fn set(&self, value: T) -> Result<(), T>

Recommendations