Skip to content
Zurück zu den Lernmaterialien

Modul 3 — Ownership, Borrowing & Slices

5. September 2026~3 min read
Lektion von 0/ abgeschlossen
Modul 3 — Ownership

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 s2s1 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

  1. Jeder Wert hat genau einen Besitzer.
  2. Fällt der Besitzer aus dem Scope, wird der Wert aufgerufen.
  3. Zuweisung und by-value Übergang verschieben (bei Copy-Typen: kopieren).

Übung: der Move

🧩 Übung m3-l1-e1

🔮 Vorhersage: Was passiert beim Ausführen?

Editor wird geladen…
KI-Tutor (sokratisch — keine Komplettlösungen)
Lektion von 0/ abgeschlossen
Modul 3 — Ownership

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?

Editor wird geladen…
KI-Tutor (sokratisch — keine Komplettlösungen)

✅ Wichtige Erkenntnisse

Haken setzen, um deinen Lernfortschritt zu markieren:

    Lektion von 0/ abgeschlossen
    Modul 3 — Ownership

    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?

    Editor wird geladen…
    KI-Tutor (sokratisch — keine Komplettlösungen)

    ✅ Wichtige Erkenntnisse

    Haken setzen, um deinen Lernfortschritt zu markieren:

      Lektion von 0/ abgeschlossen
      Modul 3 — Ownership

      Fehlermeldungen als Werkzeug

      Rust-Fehler sind Lehrmaterial. Die vier aus diesem Modul:

      CodeBedeutungtypische Ursache
      E0382use of moved valueWert nach dem Verschieben benutzt
      E0499cannot borrow as mutable more than oncezwei &mut gleichzeitig
      E0502cannot borrow as mutable because also borrowed as immutable& neben &mut
      E0106missing lifetime specifierFunktion gibt eine Referenz auf bald toten Wert zurück

      Strategie beim Lesen:

      1. Erste Fehlermeldung zuerst — spätere sind oft nur Folgen.
      2. Den Bereich (span) lesen: Welche Variable, welche Zeile?
      3. Die Hilfezeile (help:) nimmt oft eine konkrete Korrektur vorweg.
      4. 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 →

        This site uses essential cookies for Stripe payments. No tracking cookies.