Modulelessen (1/2)
De eigendomsregels
Eigendom is het meest unieke kenmerk van Rust. Het zorgt ervoor dat de taal geheugenveiligheid kan garanderen zonder dat je een Garbage Collector nodig hebt of dat je gedwongen wordt om de toewijzing van heapgeheugen handmatig ongedaan te maken (zoals in C of C++).
De drie eigendomsregels
Geheugenbeheer in Rust wordt beheerst door drie eenvoudige regels die strikt worden gecontroleerd door de compiler:
- Elke waarde in Rust heeft een variabele die de eigenaar wordt genoemd.
- Er kan slechts één eigenaar tegelijk zijn.
- Als de eigenaar buiten bereik valt, wordt de waarde automatisch verwijderd.
Stapel versus hoop
Om eigendom te begrijpen, is het belangrijk om te weten waar gegevens zich bevinden:
- Stack: slaat gegevens met een vaste grootte op die bekend zijn tijdens het compileren (bijvoorbeeld gehele getallen, booleans). De toegang is extreem snel.
- Heap: slaat gegevens van dynamische grootte op die onbekend zijn tijdens het compileren (bijvoorbeeld
String). Toewijzing is langzamer en vereist een aanwijzer die op de stapel is opgeslagen.
Het concept van ‘bewegen’
Wanneer we een door de heap toegewezen variabele aan een andere toewijzen, verplaatst (of draagt) Rust het eigendom van de waarde over, waardoor de eerste variabele ongeldig wordt:
let s1 = String::from("ciao");
let s2 = s1; // Ownership of the text moves to s2. s1 is NO longer usable!
// println!("{}", s1); // COMPILATION ERROR! s1 is "borrow of moved value"
println!("{}", s2); // Valid!Dit gedrag vermijdt de "dubbele vrije fout" (tweemaal proberen hetzelfde geheugen vrij te maken wanneer het buiten bereik valt), omdat alleen s2 het geheugen vrijmaakt.
Het concept van "kloon" (diepe kopie)
Als we expliciet de volledige inhoud van een String moeten kopiëren (zowel de stapelaanwijzers als de daadwerkelijke tekstgegevens in de heap), kunnen we de methode .clone() gebruiken. Hierdoor worden de gegevens op de heap volledig gedupliceerd, waarbij zowel de originele als de nieuwe variabele geldig blijven, ten koste van prestatieoverhead voor de nieuwe geheugentoewijzing:
let s1 = String::from("ciao");
let s2 = s1.clone(); // Deep copy. Both variables remain valid!
println!("s1: {}, s2: {}", s1, s2);Het concept van "kopiëren"
Voor eenvoudige typen die volledig op de Stack zijn opgeslagen (zoals gehele getallen i32, booleans bool, tekens char), voert de toewijzing een daadwerkelijke automatische ondiepe kopie uit, wat betekent dat beide variabelen geldig blijven:
let x = 5;
let y = x; // Copies the value 5 onto the stack. Both variables are usable!
println!("x: {}, y: {}", x, y); // Valid!Probeer het zelf
Declareer een String s1 met de tekst 'hallo'. Wijs s1 toe aan s2 (om het eigendom te verplaatsen). Tenslotte drukt u s2 af met println!.
Toon hint
Gebruik `let s2 = s1;` om het eigendom over te dragen aan `s2` en druk het af met `println!('{}', s2);`.
Oplossing beschikbaar na 3 pogingen
Declareer een geheel getal variabele x met een waarde van 5. Wijs x toe aan y (een kopie uitvoeren). Tenslotte drukt u zowel x als y af in dezelfde println! stelling.
Toon hint
Voer `let y = x;` uit en druk vervolgens beide waarden af, bijvoorbeeld `println!('{} {}', x, y);`.
Oplossing beschikbaar na 3 pogingen
Declare a String s1 with the value "Rust". Create a deep copy of s1 in a new variable s2 using the clone method. Finally, print both s1 and s2 separated by a space using the println! macro.
Toon hint
Use `let s2 = s1.clone();` to deep copy the value of `s1` into `s2`, then print them with `println!("{} {}", s1, s2);`.
Oplossing beschikbaar na 3 pogingen