🦀 Das Herzstück von Rust

Rust 02: Ownership, Move-Semantik & Borrowing (& / &mut)

Verstehe das revolutionäre Speichersicherheits-Modell von Rust ohne Garbage Collector: Stack vs. Heap, Move-Semantik, RAII (Drop), unveränderliche Referenzen und das Aliasing XOR Mutation Prinzip.

👑 1. Die drei goldenen Gesetze des Ownership-Systems

Im Gegensatz zu Sprachen mit Garbage Collector (wie Java/Python) oder manuellem Speichermanagement (wie C/C++) garantiert Rust Speichersicherheit zur Compile-Zeit durch drei strikte Regeln:

1. Einziger Eigentümer

Jeder Wert im Speicher hat zu jedem Zeitpunkt genau eine Besitzer-Variable (Owner).

2. Move-Semantik

Wird ein Wert zugewiesen oder übergeben, wandert der Besitz weiter (Move). Der alte Owner wird ungültig.

3. Automatisches Drop

Verlässt der Owner seinen Gültigkeitsbereich (Scope }), gibt Rust den Speicher sofort frei (RAII).

fn main() {
    let s1 = String::from("Rust Systems"); // s1 allokiert Heap-Speicher
    let s2 = s1;                          // ⚡ MOVE: Besitz wandert zu s2!

    // println!("{}", s1); // ❌ COMPILE-FEHLER: borrow of moved value: `s1`
    println!("{}", s2);   // ✅ s2 ist der aktuelle Eigentümer
} // Hier endet der Scope: s2 wird automatisch freigegeben (Drop)!
🚗 Didaktische Analogie: Der originale Fahrzeugbrief

Ein Heap-Objekt wie String besitzt einen Fahrzeugbrief (den Pointer auf dem Stack). Wenn du das Auto verkaufst (let s2 = s1;), übergibst du den originalen Brief. Du kannst danach nicht mehr behaupten, das Auto gehöre dir (s1 ist erloschen). So entstehen niemals Double-Free-Sicherheitslücken!

🧱 2. Stack vs. Heap & der Copy Trait

Typen mit fester Größe zur Compile-Zeit (wie i32, f64, bool, char) implementieren den Copy Trait. Bei einer Zuweisung werden sie bitweise auf dem schnellen CPU-Stack kopiert, ohne Move:

// STACK (Schnell, feste Größe, automatische Kopie):
let a: i32 = 42;
let b = a; // Beide Variablen 'a' und 'b' existieren unabhängig!

// HEAP (Dynamisch, Zeiger auf Stack):
let s1 = String::from("Hi"); // Stack: [ptr, len: 2, cap: 2] -> Heap: ['H', 'i']
let s2 = s1.clone(); // Explizite Tiefenkopie auf neuem Heap-Bereich

🤝 3. References & Borrowing: Ausleihen statt Besitzen

Möchtest du einen Wert nutzen, ohne ihn zu konsumieren, erstellst du eine Referenz (Borrowing) mit &:

Referenz-Typ Syntax Befugnis Erlaubte Anzahl gleichzeitig
Unveränderlich (Shared Borrow) &T Nur Lesen (Read-Only) Beliebig viele (∞)
Veränderbar (Mutable Borrow) &mut T Lesen & Schreiben (Read/Write) Genau eine (1)
⚖️ Die fundamentale Regel: Aliasing XOR Mutation

Du darfst zu jedem Zeitpunkt im selben Gültigkeitsbereich entweder beliebig viele unveränderliche Referenzen (&T) oder genau eine veränderliche Referenz (&mut T) haben – aber niemals beides gleichzeitig! Dies verhindert Data Races und Iterator Invalidation zur Compile-Zeit.

let mut msg = String::from("Rust");

let r1 = &msg; // Unveränderliche Ausleihe 1
let r2 = &msg; // Unveränderliche Ausleihe 2
println!("r1: {}, r2: {}", r1, r2); // ✅ Gültig!

// let r3 = &mut msg; // ❌ COMPILE-FEHLER solange r1/r2 noch aktiv genutzt werden!

let r_mut = &mut msg; // ✅ Gültig, sobald r1/r2 nicht mehr referenziert werden
r_mut.push_str(" 2024");

🎯 Aufgaben & Checkliste in aufgabe.rs

💻 In Web-IDE öffnen → Weiter zu Rust 03 →