ProgrammationDéveloppeur backend Rust

Expliquez comment fonctionne le travail avec des structures de données immuables (immutable) et mutables (mutable) en Rust, et quand la mutabilité est-elle nécessaire ? Quelles sont les limitations pratiques associées à cela, et comment peut-on les contourner habilement ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

En Rust, les structures de données sont immuables par défaut. Cela signifie que toute variable ou référence déclarée sans le mot-clé mut ne peut pas être modifiée après son initialisation.

let mut value = 10; // variable mutable value += 5; let value2 = 10; // variable immuable // value2 += 5; // erreur de compilation : cannot assign twice to immutable variable

La même logique s'applique aux champs des structures :

struct Point { x: i32, y: i32 } let mut pt = Point { x: 1, y: 2 }; pt.x = 5; // OK, car pt est déclaré comme mut

Cependant, la mutabilité n'affecte que le "niveau supérieur" de la variable : si la structure est stockée derrière une référence immuable, ses données ne peuvent pas être modifiées, même si elles sont déclarées avec mut à l'intérieur de la structure.

Une autre façon de contourner les limitations est d'utiliser des types spéciaux comme RefCell<T> ou des conteneurs atomiques. Cela permet de modifier les données à l'intérieur des conteneurs apparemment immuables en utilisant "la mutabilité intérieure" (interior mutability), par exemple :

use std::cell::RefCell; struct Counter { count: RefCell<i32>, } let counter = Counter { count: RefCell::new(0) }; *counter.count.borrow_mut() += 1; // sûr, malgré l'absence de mut

Question piégée.

Question : Peut-on changer la valeur d'un champ de structure si la variable elle-même n'est pas déclarée avec mut, mais que le champ est explicitement déclaré comme mut dans la structure elle-même ?

Réponse incorrecte typique : Oui, si le champ est déclaré avec mut, on peut le changer.

Réponse correcte : Le mot-clé mut ne peut pas être utilisé lors de la déclaration d'un champ de structure. La mutabilité concerne uniquement la variable elle-même ou la référence obtenue. Pour modifier un champ de structure, vous devez soit déclarer la variable comme mut, soit utiliser des types de "mutabilité intérieure" (par exemple, RefCell).

Exemple :

struct Foo { val: i32 } // champ déclaré sans mut let mut foo = Foo { val: 1 }; foo.val = 2; // OK let foo2 = Foo { val: 3 }; foo2.val = 4; // erreur ! variable non mutable

Exemples d'erreurs réelles dues à une mauvaise compréhension des subtilités du sujet.


Histoire

Dans un grand projet, l'un des développeurs a tenté de modifier un champ de structure, pensant que la déclaration du champ avec mut ("struct S { mut x: i32 }") donnerait la mutabilité nécessaire. Cela n'a pas pu être compilé, et le processus de refactorisation a traîné pendant plusieurs heures, jusqu'à ce qu'il lui soit expliqué que la mutabilité est une caractéristique de la possession de la variable, et non de la structure.


Histoire

Dans un projet lié à la multithreading, toute la logique de contrôle d'accès aux données était conservée dans une structure statique globale. Ne connaissant pas les possibilités de "mutabilité intérieure" via RefCell, l'équipe a écrit des mécanismes de verrouillage et de concurrence excessivement complexes, au lieu d'une solution simple via Arc<Mutex<T>> ou RwLock<T>.


Histoire

Un développeur a oublié de déclarer un argument de fonction mut à l'intérieur de la signature, et la fonction n'a pas pu modifier la structure transmise, ce qui a causé un bug qui s'est manifesté uniquement en production (les données n'étaient pas mises à jour après l'appel de la fonction). Savoir que par défaut le passage se fait par référence immuable lui aurait permis d'éviter une erreur à un stade précoce.