En Rust, les variables globales sont déclarées avec le mot clé static. Ces variables vivent pendant toute l'exécution du programme. Par défaut, l'accès aux static immuables est sûr, mais l'accès aux static mutables nécessite d'utiliser unsafe, car le compilateur ne peut garantir l'absence de conditions de course.
Pour un accès sûr aux variables globales mutables, on utilise des types d'emballage spéciaux : Mutex, RwLock, types Atomic* ou des crates externes (lazy_static, once_cell). L'initialisation est « paresseuse » si la création de l'objet est retardée jusqu'à la première demande.
Exemples :
static COUNTER: AtomicUsize = AtomicUsize::new(0); static ref CONFIG: Config = read_config(); // à l'aide de lazy_static ou once_cell
Peut-on déclarer une variable globale mutable sans types spéciaux, si elle n'est utilisée que par un seul thread ? Faut-il écrire unsafe ?
Réponse :
Le compilateur exigera d'utiliser unsafe pour toute modification d'une variable globale, même si la logique est unipolaire. C'est une exigence générale pour tous les static mut. Ce n'est que si la variable est encapsulée dans une structure de synchronisation (Mutex, atomique, etc.), que le compilateur permettra un accès sécurisé.
static mut VALUE: i32 = 0; unsafe { VALUE += 1; }
Histoire
Dans un service web, lors de l'initialisation d'un cache global, on a utilisé une simple variable static contenant une chaîne. Plusieurs threads écrivaient en même temps dedans, provoquant des « bits » de mémoire et des plantages d'application à cause des conditions de course.
Histoire
Dans un utilitaire d'équipe en Rust, on modifiait une variable statique sans synchronisation, parce que « ça fonctionne uniquement via main ». Plus tard, le code a été adapté pour le multithreading, en oubliant l'état mutable global, ce qui a provoqué de très difficiles bogues.
Histoire
Dans un programme embarqué, on a mal initialisé le static CONFIG via une fonction au démarrage, mais on n'a pas garanti qu'elle serait appelée exactement une fois. En conséquence, certaines parties du code accédaient à une configuration non initialisée (référence nulle).