ProgrammatieBackend ontwikkelaar

Wat is het verschil tussen het gebruik van move en borrow bij het doorgeven van variabelen aan functies in Rust?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

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.

Misleidende vraag

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.

Voorbeelden van echte fouten door onwetendheid over nuances in dit onderwerp


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.