Wanneer een variabele aan een functie wordt doorgegeven, kan deze ofwel via een referentie (borrow, met & of &mut) worden doorgegeven, of worden verplaatst (move, zonder referentie).
Borrow: een referentie naar de gegevens wordt doorgegeven. De gegevens blijven toegankelijk na de functieaanroep, maar voor een ongewijzigde referentie kan de inhoud niet worden gewijzigd, en voor een gewijzigde referentie mag er maar 1 actieve referentie zijn.
fn read_length(s: &String) -> usize { s.len() }
Move: de variabele "verhuist" volledig naar de functie. Na doorgeven kunt u de oorspronkelijke variabele niet meer gebruiken - deze is verplaatst, en elke poging om deze te benaderen resulteert in een compilatiefout.
fn destroy(s: String) { println!("{}", s); } // s wordt vernietigd bij het verlaten van de functie let s = String::from("world"); destroy(s); // s kan niet meer worden gebruikt
Dit voorkomt dubbele geheugenbevrijding en andere eigendomsfouten.
Kan ik een variabele gebruiken nadat deze met waarde (move) aan een functie is doorgegeven?
Nee! Na het doorgeven van een variabele met waarde - bijvoorbeeld, String - wordt de oorspronkelijke variabele ongeldig:
let s = String::from("abc"); consume(s); // s is hier niet meer geldig println!("{}", s); // compilatiefout
Veel mensen verwarren dit met het gedrag van types met Copy (bijvoorbeeld i32), waar de variabele geldig blijft na doorgeven.
Verhaal
Een jonge programmeur schreef een functie voor het verwerken van een string die String accepteerde in plaats van &String. Hierdoor werd de oorspronkelijke string na de functieaanroep onbereikbaar, wat leidde tot dubbele belastingen en extra geheugentoewijzing in de logserver.
Verhaal
In een microservice werd een kritieke resource doorgegeven aan verschillende threads via move, waarna pogingen om deze resource in de hoofdthread te benaderen leidden tot een compilatiefout. Het was noodzakelijk om de architectuur snel te refactoren zodat de resource via een referentie of via wrappers zoals Arc werd doorgegeven.
Verhaal
In de interne gebeurtenisparser werd de variabele tijdelijk verplaatst (move) naar een closure tijdens de gegevensverwerking, waarna toegang tot deze variabele buiten de closure compilatiefouten veroorzaakte. Het probleem werd alleen opgemerkt tijdens de review - er werd een stijl geïntroduceerd die verplichtte om borrow te gebruiken voor gegevens die langer dan de lokale functie moesten leven.