Modul 3 — Ownership, Borrowing & Slices
Ownership & der Move
Jeder Wert hat genau einen Besitzer. Fällt der Besitzer aus dem Scope, wird der Wert aufgerufen (Speicher frei, ohne Garbage Collector). Was passiert bei einer Zuweisung?
fn main() {
let s1 = String::from("hello");
let s2 = s1; // MOVE: s2 besitzt die Heap-Daten jetzt
// println!("{s1}"); // ❌ E0382: value borrowed after move
println!("{s2}");
}
String verwaltet einen Heap-Puffer. Statt ihn heimlich zu kopieren,
verschiebt Rust die Verantwortung zu s2 — s1 ist danach tabu. Das
erledigt doppelte Freigabe und Use-after-free zur Compile-Zeit.
Copy-Types bewegen sich nicht
fn main() {
let a = 5;
let b = a; // i32: Copy — einfachere Kopie
println!("{a} {b}"); // 5 5 — beide gültig
}
Ganze Zahlen, Gleitkommazahlen, bool, char und Tupel daraus implementieren
Copy: Zuweisung kopiert bitweise, das Original bleibt gültig. Alles mit
Heap-Beteiligung (String, Vec, ...) verschiebt sich.
Moves passieren bei jedem by-value Übergang
fn consume(s: String) {
println!("{s}");
} // s wird hier aufgerufen — Speicher frei
fn main() {
let s = String::from("hi");
consume(s); // Ownership wandert in die Funktion
// consume(s); // ❌ E0382 — s ist weg
}
Willst du den Wert behalten: consume(s.clone()) (explizite Tiefkopie) oder
besser — nächste Lektion — nur leihen.
Die drei Ownership-Regeln
- Jeder Wert hat genau einen Besitzer.
- Fällt der Besitzer aus dem Scope, wird der Wert aufgerufen.
- Zuweisung und by-value Übergang verschieben (bei Copy-Typen: kopieren).
Übung: der Move
🧩 Übung m3-l1-e1
🔮 Vorhersage: Was passiert beim Ausführen?
Borrowing: &, &mut und NLL
Statt Ownership abzugeben, leihst du einen Wert:
fn len(s: &String) -> usize { // & = nur leihen
s.len()
} // Der Kredit endet — nichts wird aufgerufen
fn main() {
let s = String::from("rust");
let n = len(&s);
println!("{s} hat {n} Bytes"); // ✅ s gehört weiterhin uns
}
Die Aliasing-Regel
Zu jedem Zeitpunkt gilt: entweder beliebig viele unveränderliche Referenzen
&T, oder genau eine veränderliche &mut T. Nie beides gleichzeitig.
fn main() {
let s = String::from("hello");
let r1 = &s;
let r2 = &s; // ✅ viele gemeinsame Kredite sind in Ordnung
println!("{r1} {r2}");
}
fn main() {
let mut s = String::from("hi");
let a = &mut s;
let b = &mut s; // ❌ E0499: cannot borrow as mutable more than once
println!("{a}{b}");
}
Warum diese Härte? Ein Schreiber neben vielen Lesern wäre eine Data Race in Wartezeit. Die Regel macht ganze Klassen von Fehlern unmöglich — zur Compile-Zeit, ohne Laufzeitkosten.
E0502: wenn Lesen und Schreiben kollidieren
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
let r3 = &mut s; // ❌ E0502 — r1/r2 werden danach noch gelesen
println!("{r1} {r2} {r3}");
}
NLL: Der Kredit endet an der letzten Nutzung
Borrows leben nicht bis zum Scope-Ende, sondern bis zu ihrer letzten Verwendung (Non-Lexical Lifetimes, seit Rust 2018):
fn main() {
let mut s = String::from("hello");
let r = &s;
println!("{r}"); // letzte Nutzung von r — Kredit endet hier
s.push_str(" world"); // ✅ deshalb legal
println!("{s}");
}
Und der Klassiker: clear() während word noch ausleiht:
fn first_word(s: &str) -> &str {
s.split_whitespace().next().unwrap_or("")
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // ❌ E0502 — word wird darunter noch gelesen
println!("{word}");
}
Der Borrow-Checker verbietet dir hier, versehentlich einen Zeiger auf geschrubte Daten zu behalten. In C wäre das ein stiller Bug.
Leser oder Schreiber — nie beides
Gleichzeitig erlaubt: &T beliebig oft oder &mut T genau einmal.
Referenzen müssen immer gültig bleiben (kein Dangling). Das ist die
gesamte Kernregel des Borrow-Checkers — alles Weitere sind Details.
Übung: der Doppelkredit
🧩 Übung m3-l2-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Slices & &str
Ein Slice ist eine Ansicht (fat pointer: Zeiger + Länge) in vorhandene Daten — kein Kopieren:
fn main() {
let s = String::from("hello world");
let w = &s[0..5]; // &str — leiht die ersten 5 Bytes
println!("{w}"); // hello
}
&str ist der universelle String-Typ fürs Lesen: String-Literale sind &str,
und &String wird automatisch in &str umgewandelt (deref coercion).
Deshalb nimmt man in Funktionsparametern &str, nicht &String:
fn greet(name: &str) -> String {
format!("Hello, {name}!")
}
fn main() {
greet("Rust"); // &str literal
let owned = String::from(" YOU ");
greet(&owned); // &String → &str — coercion
}
Als Parameter: &str — der Aufrufer kann Literale, Slices und String
gleichermaßen übergeben. String als Parameter erzwingt Besitztransfer oder
Klonen, &String schließt Literale aus — beides schlechter.
Slice = Zeiger + Länge
Ein &str kopiert keine Bytes, er zeigt hinein. Deshalb ist die zurückgegebene
first_word-Referenz an die Lebensdauer des Ursprungs-Strings gebunden —
dafür braucht es später Lifetime-Annotationen (Modul 9).
Übung: das erste Wort
🧩 Übung m3-l3-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Fehlermeldungen als Werkzeug
Rust-Fehler sind Lehrmaterial. Die vier aus diesem Modul:
| Code | Bedeutung | typische Ursache |
|---|---|---|
E0382 | use of moved value | Wert nach dem Verschieben benutzt |
E0499 | cannot borrow as mutable more than once | zwei &mut gleichzeitig |
E0502 | cannot borrow as mutable because also borrowed as immutable | & neben &mut |
E0106 | missing lifetime specifier | Funktion gibt eine Referenz auf bald toten Wert zurück |
Strategie beim Lesen:
- Erste Fehlermeldung zuerst — spätere sind oft nur Folgen.
- Den Bereich (span) lesen: Welche Variable, welche Zeile?
- Die Hilfezeile (
help:) nimmt oft eine konkrete Korrektur vorweg. - Frag den KI-Tutor (Button in jeder Übung) — er erklärt, statt die Lösung zu verraten.
📝 Schnellprüfung
Was bedeutet E0502?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Modul-Checkpoint
Checkpoint: Modul 3
Bestehensgrenze: 80 %. Der Versuch wird bewertet und zählt für das Modul-Gate.
Bereit, dein Wissen zu testen?
Probiere unsere Übungsprüfungen mit Hunderten von realistischen Fragen aus.
Üben starten →