Quando una variabile viene passata a una funzione, può essere passata per riferimento (borrow, utilizzando & o &mut), oppure può essere spostata (move, senza riferimento).
Borrow: viene passato un riferimento ai dati. I dati rimangono accessibili dopo la chiamata della funzione, ma per un riferimento immutabile non è possibile modificare il contenuto, mentre per un riferimento mutabile può esserci solo 1 riferimento attivo.
fn read_length(s: &String) -> usize { s.len() }
Move: la variabile viene "trasferita" interamente nella funzione. Dopo il passaggio non è possibile utilizzare la variabile originale — è stata spostata e qualsiasi tentativo di accesso genererà un errore di compilazione.
fn destroy(s: String) { println!("{}", s); } // s verrà distrutta all'uscita let s = String::from("world"); destroy(s); // s non può più essere utilizzata
Questo previene la doppia liberazione della memoria e altri errori di possesso.
Posso usare la variabile dopo che è stata passata alla funzione per valore (move)?
No! Dopo che la variabile è stata passata per valore — ad esempio, String — la variabile originale diventa non valida:
let s = String::from("abc"); consume(s); // s non è più valida qui println!("{}", s); // errore di compilazione
Molti confondono questo comportamento con quello dei tipi con Copy (ad esempio, i32), dove la variabile rimane valida dopo il passaggio.
Storia
Un giovane programmatore ha scritto una funzione di elaborazione delle stringhe che accettava String e non &String. Di conseguenza, la stringa originale diventava non accessibile dopo la chiamata della funzione, portando a un caricamento doppio e a un'allocazione di memoria aggiuntiva nel server di registrazione.
Storia
In un microservizio, una risorsa critica veniva passata a diversi thread tramite move, dopo di che i tentativi di accesso a questa risorsa nel thread principale portavano a errori di compilazione. È stato necessario rifattorizzare urgentemente l'architettura affinché la risorsa fosse passata per riferimento o tramite wrapper come Arc.
Storia
Nel parser eventi interno, durante l'elaborazione dei dati, la variabile veniva rapidamente spostata (move) in una closure, dopo di che gli accessi ad essa al di fuori della closure generavano errori di compilazione. Il problema è stato notato solo durante la revisione — è stato introdotto uno stile di utilizzo obbligatorio di borrow per i dati che devono vivere più a lungo della funzione locale.