Begriff
Borrow Checker
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Der Türsteher von Rust.
In anderen Sprachen (C++) kannst du Speicher freigeben (free), aber noch eine Referenz darauf behalten ("Dangling Pointer").
Wenn du die Referenz später nutzt -> Crash oder Hack.
Der Borrow Checker ist ein Teil des Rust-Compilers, der deinen Code analysiert.
Er prüft jede Referenz:
Lebt der Besitzer (Owner) noch?
Musterantwort: Beginne mit dem konkreten Fall, prüfe die Fakten und erkläre den Begriff daran. Für diesen Abschnitt gilt: Du merkst ihn nur, wenn er meckert. Typischer Fehler: let r; { let x = 5; r = &x; } println!("{}", r); Fehler: x stirbt am Ende des Blocks {}. r würde auf toten Speicher zeigen. Der Borrow Checker sagt: "Borrowed value does not live long enough." Lösung: Struktur des Codes ändern, damit x länger lebt.- Gibt es gleichzeitig jemanden, der schreibt? Wenn er auch nur den Hauch eines Zweifels hat, lehnt er den Code ab. Er ist berüchtigt dafür, Anfänger in den Wahnsinn zu treiben ("Borrow Checker Errors"). Aber er rettet dich vor Bugs, die du sonst erst nach Wochen in Produktion finden würdest.
Merksatz: Die Komponente des Rust-Compilers, die zur Kompilierzeit die Regeln des Ausleihens (Borrowing) und der Lebensdauer (Lifetimes) von Referenzen erzwingt, um Speichersicherheit und Datenwettlauffreiheit zu garantieren.
Du merkst ihn nur, wenn er meckert.
Typischer Fehler:
let r; { let x = 5; r = &x; } println!("{}", r);
Fehler: x stirbt am Ende des Blocks {}. r würde auf toten Speicher zeigen.
Der Borrow Checker sagt: "Borrowed value does not live long enough."
Lösung: Struktur des Codes ändern, damit x länger lebt.
1. NLL (Non-Lexical Lifetimes)
Früher war der Borrow Checker dumm (Scope-basiert). Seit Rust 2018 gibt es NLL. Er versteht den Control Flow Graph. "Variable x wird hier zuletzt benutzt. Danach ist der Borrow zu Ende (auch wenn der Scope noch offen ist)." Das macht ihn viel freundlicher.
2. Polonius
Der Name des neuen Borrow Checkers (noch in Entwicklung). Er basiert auf Datalog (Logik-Programmierung). Er soll noch schlauer werden und Fälle erlauben, die heute irrtümlich abgelehnt werden ("Self-Referential Structs").
1. Variance (Subtyping & Lifetimes)
Das ist das Endgegner-Thema für Rust-Profis.
Lifetimes verhalten sich wie Typen in einer Hierarchie. Eine 'static Lifetime (lebt ewig) ist ein "Subtyp" von einer kürzeren 'a Lifetime.
Der Borrow Checker muss entscheiden, ob man eine lange Lifetime dort einsetzen darf, wo eine kurze erwartet wird (Covariance) oder ob das verboten ist (Invariance).
Beispiel: Bei einer &T Referenz ist Rust kovariant (du kannst was Längeres reinstecken). Bei einem &mut T (schreibbar) ist es invariant, da sonst ein Pointer auf ein kurzlebiges Objekt in eine langlebige Struktur geschmuggelt werden könnte, was nach dem Free zu einem Crash führen würde.
2. Polonius & Datalog-based Analysis
Der aktuelle Borrow Checker nutzt einen Algorithmus namens "NLL". Dieser ist zwar gut, hat aber theoretische Schwächen bei komplexen Schleifen. Polonius ist das Forschungsprojekt, das den Borrow Checker auf eine rein logische Basis stellt. Anstatt den Code Zeile für Zeile zu scannen, wird der Code in Fakten übersetzt:
origin_contains_loan(L, P)(Punkt P enthält Kredit L).placeholder_is_subset(A, B)(A muss länger leben als B). Dann lässt man eine Logik-Engine (Datalog) darüber laufen. Das erlaubt es, Fälle wie "reborrowing in a loop" mathematisch korrekt zu lösen, die heute noch mit hässlichen Workarounds (Option::take) umgangen werden müssen.
3. Stack Pinning & Self-referential Structs
Rust hat ein Problem mit Strukturen, die auf sich selbst zeigen (z. B. ein Async Future, das lokale Variablen speichert).
Wenn man so eine Struktur im Speicher verschiebt (Move), würden die internen Pointer plötzlich ins Leere zeigen.
Der Borrow Checker verhindert solche Strukturen normalerweise komplett.
Dafür gibt es das Pinning (Pin<P>). Es ist ein Versprechen an den Borrow Checker: "Ich garantiere, dass dieses Objekt niemals im Speicher verschoben wird." Erst durch dieses komplexe Zusammenspiel von Borrow Checker und Memory Layout ist hocheffizientes asynchrones Programmieren in Rust ohne CPU-Overhead möglich.
Quick-Check
Laufzeitkosten?
Null. Der Borrow Checker läuft nur beim Kompilieren. Das fertige Binary enthält keine Checks (und keinen GC).Data Races?
Er verhindert Data Races komplett. Er erlaubt&mut T(Schreiben) nur, wenn kein anderer&T(Lesen) hat. "Aliasing XOR Mutation".Interior Mutability?
Manchmal muss man die Regeln brechen (z. B. Reference Counting). Typen wieRefCelloderMutexprüfen die Regeln zur Laufzeit (Runtime Check) statt zur Compile-Zeit.