In Rust non esiste un garbage collector classico, quindi per gestire la proprietà di strutture complesse si utilizzano puntatori intelligenti (smart pointers). I più comunemente usati sono:
Box<T> — alloca memoria per un oggetto nel heap e trasferisce la sua proprietà. È usato nei casi in cui la dimensione dei dati non è nota durante la compilazione o è necessario un risorsa spostabile ma unica.
Rc<T> (Reference Counted) — conteggio dei riferimenti, consente a più variabili di "condividere" la proprietà di dati immutabili (solo in un contesto monothread).
Arc<T> (Atomic Reference Counted) — implementa anche il conteggio dei riferimenti, ma è atomico; è utilizzato nei programmi multithread.
RefCell<T> — fornisce proprietà "internamente mutabile" a runtime, consentendo di cambiare il contenuto anche attraverso un riferimento immutabile, ma solo in un singolo thread (non è thread-safe!).
Esempio:
use std::rc::Rc; let a = Rc::new(vec![1,2,3]); let b = Rc::clone(&a); // Ora sia a che b sono proprietari degli stessi dati
È possibile utilizzare Rc<T> nel codice multithread, se tutti i thread leggono solo i dati? Spiega.
Risposta: No, non è possibile! Anche se Rc<T> consente solo l'accesso immutabile ai dati, il contenitore stesso Rc<T> non è thread-safe, poiché il numero interno di riferimenti non è protetto dalle condizioni di gara. A questo scopo è destinato Arc<T>, il cui contatore interno è thread-safe.
Esempio:
// Il seguente codice non compila! use std::thread; use std::rc::Rc; let five = Rc::new(5); for _ in 0..10 { let five = Rc::clone(&five); thread::spawn(move || { println!("{}", five); }); }
Storia
Storia
Storia
Nel modulo di logica aziendale hanno utilizzato RefCell<T> per organizzare l'accesso mutabile ai dati, che venivano anche trasferiti tramite Arc<T> tra i thread. Ma cercare di combinare RefCell<T> e Arc<T> ha portato a condizioni di gara e panico durante l'esecuzione. Per una versione thread-safe sarebbe stato meglio usare Mutex<T> o RwLock<T> al posto di RefCell<T>.