Praxisteil & Übungen: Speicherverwaltung, Ownership und Referenzen
Dieser Praxisteil führt Sie Schritt für Schritt durch das Verständnis von Besitzrechten (Ownership) und Ausleihen (Borrowing) in Rust.
1. Praxis-Szenario: Das Transaktions-Verarbeitungsmodul eines Banksystems
Sie arbeiten als Entwickler bei einer Bank. Sie schreiben ein Modul zur Erfassung von Überweisungen, das Daten ressourcenschonend liest und den Verarbeitungsstatus modifiziert.
Die Übungsaufgabe befindet sich im Verzeichnis:
- exercises/02_ownership/src/main.rs (Starten Sie hier mit einer leeren
main()-Funktion)
2. Strukturierte Praxis-Einheiten
2.1 Get Started: Ownership & Move-Semantik
In Rust besitzt eine Variable einen Wert und der Besitz wird bei Zuweisungen standardmäßig übertragen (Move).
Beispiel:
#![allow(unused)]
fn main() {
let s1 = String::from("Rust");
let s2 = s1; // s1 ist ab hier ungültig!
}
Erklärung:
- String::from: Erstellt ein String-Objekt auf dem Heap.
- let s2 = s1: Überträgt das Besitzrecht von
s1aufs2, um Double-Free-Fehler beim Verlassen des Gültigkeitsbereichs zu verhindern.
Aufgabe:
Deklarieren Sie in Ihrer main()-Funktion eine String-Variable s1 mit dem Wert "Rust".
2.2 Unveränderliches Ausleihen (Referenzen &)
Referenzen ermöglichen es, Werte auszuleihen, ohne dass der Besitz übertragen wird.
Beispiel:
#![allow(unused)]
fn main() {
fn anzeigen(s: &String) {
println!("{}", s);
}
}
Erklärung:
- &String: Typ einer unveränderlichen Referenz auf einen String. Der Besitzer bleibt die aufrufende Funktion.
Aufgabe:
- Schreiben Sie eine Funktion
anzeigen, die eine unveränderliche String-Referenz (&String) als Parameter entgegennimmt und diese ausgibt. - Rufen Sie
anzeigeninmain()mit einer Referenz aufs1(&s1) auf und geben Sies1danach erneut inmain()aus.
2.3 Veränderbares Ausleihen (&mut)
Um geliehene Werte zu modifizieren, müssen Sie eine veränderliche Referenz deklarieren.
Beispiel:
#![allow(unused)]
fn main() {
fn hinzufuegen(s: &mut String) {
s.push_str("pfad");
}
}
Erklärung:
- &mut String: Typ einer veränderlichen Referenz. Es darf zu jedem Zeitpunkt nur genau eine veränderliche Referenz existieren.
Aufgabe:
- Schreiben Sie eine Funktion
hinzufuegen, die eine veränderliche String-Referenz (&mut String) als Parameter entgegennimmt und übers.push_str("pfad")Text anhängt. - Deklarieren Sie in
main()eine veränderbare String-Variables2mit dem Wert"Lern". - Rufen Sie
hinzufuegenmit einer veränderlichen Referenz aufs2(&mut s2) auf und geben Sies2danach aus.
3. Genaue Code-Erklärung der Musterlösung
Der fertige Code der Musterlösung befindet sich unter solutions/02_ownership/src/main.rs:
1: // Musterlösung zu Übung 2: Ownership & Borrowing
2: // Alle Anforderungen wurden erfolgreich implementiert.
3:
4: fn main() {
5: // 1. Zuweisung und Übergabe als unveränderliche Referenz (&String)
6: let s1 = String::from("Rust");
7: anzeigen(&s1); // Wir übergeben nur eine Referenz (kein Ownership-Transfer)
8: println!("Der String '{}' ist nach dem Anzeigen immer noch gültig!", s1);
9:
10: // 2. Erstellen und Übergabe einer veränderlichen Referenz (&mut String)
11: let mut s2 = String::from("Lern");
12: hinzufuegen(&mut s2); // Wir verleihen veränderbaren Zugriff
13: println!("Geändertes Wort: {}", s2);
14: }
15:
16: // NIMMT REFERENZ ENTGEGEN: s hat den Typ &String
17: fn anzeigen(s: &String) {
18: println!("Wort: {}", s);
19: }
20:
21: // NIMMT VERÄNDERLICHE REFERENZ ENTGEGEN: s hat den Typ &mut String
22: fn hinzufuegen(s: &mut String) {
23: s.push_str("pfad");
24: }
Zeilen-Analyse der Lösung:
- Zeile 6:
let s1 = String::from("Rust");– Deklariert das String-Objekt auf dem Stack, welches auf den Heap-Speicher zeigt. - Zeile 7:
anzeigen(&s1);– Leihts1unveränderlich aus. Da der Besitz nicht übertragen wird, bleibts1inmain()gültig. - Zeile 11:
let mut s2 = String::from("Lern");– Erstellt eine veränderbare String-Variable auf dem Stack. - Zeile 12:
hinzufuegen(&mut s2);– Übergibt eine veränderbare Referenz anhinzufuegen. - Zeile 17–19: Die Funktion
anzeigenliest den Wert übersaus. Nach dem Funktionsende wird nur die Referenz vom Stack gelöscht. - Zeile 21–24: Die Funktion
hinzufuegengreift übersdirekt auf den Heap-Speicher vons2zu und hängt die Bytes"pfad"an.