👑 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)!
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:
🤝 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) |
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");