Singleton global en Rust : brisons les stéréotypes avec du code

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

Introduction : pourquoi un singleton global en Rust est-il un défi ?

\n\n

Si vous venez du monde Python, JavaScript ou C++, vous êtes habitué à un simple objet global. Vous déclarez une variable au niveau du module – et elle est à vous. En Rust, cette astuce ne fonctionne pas. Le compilateur surveille strictement la durée de vie et l'accès aux données, surtout si elles peuvent être modifiées depuis différents threads. C'est pourquoi sur Stack Overflow, la question « How do I create a global, mutable singleton? » a recueilli des milliers de vues et des dizaines de réponses complexes.

\n\n

Mais ne vous inquiétez pas. Le singleton en Rust n'est pas une douleur, mais une discipline. Aujourd'hui, nous allons voir comment créer un singleton mutable global de manière sécurisée, efficace et en comprenant ce qui se passe. Vous apprendrez pourquoi static mut est un mal, et quels outils (lazy_static, OnceCell, Mutex) nous donnent le contrôle.

\n\n

Cet article est écrit pour le site éducatif pythonlib.ru et adapte une question réelle de SO en leçon pratique. C'est parti !

\n\n

Le problème : qu'est-ce qu'un singleton mutable global ?

\n\n

Singleton est un modèle de conception où une classe ou une structure a exactement une instance dans tout le programme. Dans le contexte de Rust, nous parlons d'une variable globale accessible depuis n'importe où dans le code, que l'on peut modifier (mut).

\n\n

Exemples d'utilisation :

\n
    \n
  • Configuration de l'application, chargée une fois au démarrage.
  • \n
  • Logger global ou compteur d'événements.
  • \n
  • Pool de connexions à une base de données.
  • \n
  • Cache en mémoire (in-memory cache).
  • \n
\n\n

Le problème est que Rust interdit les variables globales mutables sans wrapper spécial. Pourquoi ? Parce qu'elles entraînent des courses de données (data races) et un comportement indéfini. Le compilateur ne peut pas prouver que deux threads n'écriront pas simultanément dans la même cellule mémoire.

\n\n

La solution naïve ressemble à ceci :

\n
// MAUVAIS code — ne faites pas ça !\nstatic mut COUNTER: u32 = 0;\n\nfn increment() {\n    unsafe {\n        COUNTER += 1;\n    }\n}\n
\n

Cela fonctionne, mais nécessite unsafe et vous laisse seul face aux courses. Dans un environnement multi-thread, c'est une bombe à retardement. Nous avons besoin d'une approche sûre et idiomatique.

\n\n

Outil 1 : lazy_static + Mutex — le classique du genre

\n\n

La façon la plus populaire de créer un singleton mutable global est la combinaison de lazy_static (initialisation paresseuse) et Mutex (exclusion mutuelle).

\n\n

Ajoutez les dépendances dans Cargo.toml :

\n
[dependencies]\nlazy_static = "1.4"\n
\n\n

Maintenant le code :

\n
use lazy_static::lazy_static;\nuse std::sync::Mutex;\n\nlazy_static! {\n    static ref GLOBAL_CONFIG: Mutex<Config> = Mutex::new(Config::default());\n}\n\n#[derive(Debug)]\nstruct Config {\n    db_url: String,\n    max_connections: u32,\n}\n\nimpl Default for Config {\n    fn default() -> Self {\n        Config {\n            db_url: "localhost:5432".to_string(),\n            max_connections: 10,\n        }\n    }\n}\n\nfn main() {\n    // Lecture\n    let config = GLOBAL_CONFIG.lock().unwrap();\n    println!("URL actuelle : {}", config.db_url);\n\n    // Écriture\n    // drop(config); // libère explicitement le verrou\n    let mut config = GLOBAL_CONFIG.lock().unwrap();\n    config.db_url = "new-host:8888".to_string();\n    println!("Nouvelle URL : {}", config.db_url);\n}\n
\n\n

Comment cela fonctionne-t-il ?

\n
    \n
  • lazy_static! garantit que l'initialisation n'a lieu qu'une seule fois lors de la première utilisation.
  • \n
  • Mutex<T> assure l'exclusion mutuelle : un seul thread peut accéder aux données à un moment donné.
  • \n
  • La méthode .lock() retourne un MutexGuard qui libère automatiquement le verrou en sortant de la portée.
  • \n
\n\n

Avantages : simplicité, éprouvé par le temps, sûr pour

Blogs

Book Recommendations