In Rust, le strutture dati sono di default immutabili. Ciò significa che qualsiasi variabile o riferimento dichiarato senza la parola chiave mut non può essere modificato dopo l'inizializzazione.
let mut value = 10; // variabile mutabile value += 5; let value2 = 10; // variabile immutabile // value2 += 5; // errore di compilazione: cannot assign twice to immutable variable
La stessa logica si applica ai campi delle strutture:
struct Point { x: i32, y: i32 } let mut pt = Point { x: 1, y: 2 }; pt.x = 5; // OK, dato che pt è dichiarato come mut
Tuttavia, la mutabilità riguarda solo il "livello superiore" della variabile: se la struttura è memorizzata dietro un riferimento immutabile, i suoi dati non possono essere modificati, anche se sono dichiarati con mut all'interno della struttura.
Un altro modo per aggirare le limitazioni è usare tipi speciali come RefCell<T> o contenitori atomici. Questo consente di modificare i dati all'interno di contenitori che sembrano immutabili usando la "mutabilità interna" (interior mutability), ad esempio:
use std::cell::RefCell; struct Counter { count: RefCell<i32>, } let counter = Counter { count: RefCell::new(0) }; *counter.count.borrow_mut() += 1; // sicuro, nonostante l'assenza di mut
Domanda: Si può cambiare il valore di un campo di una struttura se la variabile stessa non è dichiarata con mut, ma il campo è chiaramente dichiarato come mut nella struttura stessa?
Risposta tipica errata: Sì, se il campo è dichiarato con mut, può essere cambiato.
Risposta corretta: La parola chiave mut non può essere utilizzata quando si dichiara un campo di una struttura. La mutabilità si riferisce solo alla variabile stessa o al riferimento ottenuto. Per modificare un campo della struttura, si deve dichiarare la variabile come mut oppure usare tipi di "mutabilità interna" (ad esempio, RefCell).
Esempio:
struct Foo { val: i32 } // campo dichiarato senza mut let mut foo = Foo { val: 1 }; foo.val = 2; // OK let foo2 = Foo { val: 3 }; foo2.val = 4; // errore! variabile non mutabile
Storia
In un grande progetto, uno degli sviluppatori ha tentato di modificare un campo di una struttura, pensando che dichiarare il campo con mut ("struct S { mut x: i32 }") avrebbe fornito la necessaria mutabilità. Questo non è riuscito a compilarsi, e il processo di refactoring è stato ritardato di diverse ore, finché non è stato spiegato che la mutabilità è una caratteristica della proprietà della variabile, non della struttura.
Storia
In un progetto legato alla multithreading, tutta la logica di controllo dell'accesso ai dati era mantenuta in una struttura statica globale. Non essendo a conoscenza delle possibilità di "mutabilità interna" tramite
RefCell, il team scriveva meccanismi complessi e ridondanti di blocco e race condition, invece di una semplice soluzione tramiteArc<Mutex<T>>oRwLock<T>.
Storia
Un developper ha dimenticato di dichiarare l'argomento della funzione come mut all'interno della firma, e la funzione non è riuscita a modificare la struttura passata, il che ha fatto sì che il bug si manifestasse solo in produzione (i dati non si aggiornavano dopo la chiamata della funzione). Sapere che per default il passaggio avviene tramite riferimento immutabile gli avrebbe permesso di evitare errori nei primi stadi.