Warum braucht Rust explizite Lebensdauern? Erklärt anhand von Beispielen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum zwingt Rust einen, Lebensdauern anzugeben? Und wie vereinfacht das das Leben?

\n\n

Wenn Sie Rust lernen, stoßen Sie früher oder später auf diese mysteriöse Syntax: 'a, 'b... Und es stellt sich die berechtigte Frage: „Warum muss ich explizit Lebensdauern angeben? Andere Sprachen kommen doch auch ohne aus!“

\n\n

Diese Frage ist eine der beliebtesten auf Stack Overflow (tausende Aufrufe). Und das ist nicht verwunderlich: Das Konzept der Lifetimes in Rust erscheint kompliziert, bis man sein Wesen versteht. Lassen Sie es uns ohne langweilige Theorie anhand von lebendigen Beispielen klären.

\n\n

Kurze Antwort: Sicherheit ohne Garbage Collector

\n\n

Rust garantiert Speichersicherheit zur Kompilierzeit. Es muss genau wissen, wie lange Referenzen leben, um hängende Referenzen (dangling references) zu verhindern. In Java oder Go kümmert sich der Garbage Collector darum. In C++ sind Sie selbst für den Speicher verantwortlich (und machen oft Fehler). Rust hat einen dritten Weg gewählt: Der Compiler überprüft alles statisch.

\n\n

Aber warum kann der Compiler nicht selbst darauf kommen? Kann er – in 80% der Fälle. Das nennt man Lifetime Elision (Regeln zur impliziten Ableitung). In komplexen Situationen benötigt er jedoch Ihre Hilfe.

\n\n

Regel Nr. 1: Der Compiler ist kein Hellseher

\n\n

Schauen Sie sich diese Funktion an:

\n\n
fn longest(x: &str, y: &str) -> &str {\n    if x.len() > y.len() { x } else { y }\n}
\n\n

Auf den ersten Blick ist alles logisch. Aber Rust gibt einen Fehler aus: „missing lifetime specifier“. Warum?

\n\n

Stellen Sie sich vor, Sie übergeben x – eine Referenz auf einen String, der 5 Sekunden lebt, und y – eine Referenz auf einen String, der 1 Sekunde lebt. Die Funktion kann jeden von ihnen zurückgeben. Wie groß ist die Lebensdauer der zurückgegebenen Referenz? Der Compiler weiß es nicht!

\n\n

Die Lösung – explizit sagen: „Die zurückgegebene Referenz wird genauso lange leben wie beide Eingaben“:

\n\n
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {\n    if x.len() > y.len() { x } else { y }\n}
\n\n

Das Symbol 'a ist eine Lebensdauer-Annotation. Wir sagen: „Alle drei Referenzen müssen die gleiche minimale Lebensdauer haben“. Jetzt kann der Compiler überprüfen, dass der aufrufende Code die Daten nicht vorzeitig zerstört.

\n\n

Regel Nr. 2: Unterschiedliche Referenzen – unterschiedliche Lebensdauern

\n\n

Ein häufiger Anfängerfehler ist zu denken, dass alle 'a gleich sein müssen. Tatsächlich kann man unterschiedliche Lebensdauern angeben:

\n\n
fn example<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {\n    x // Ok, wir geben eine Referenz mit der Lebensdauer 'a zurück\n    // y // Fehler! y lebt 'b, aber wir haben 'a versprochen\n}
\n\n

Hier sagen wir explizit: x und y können unterschiedliche Lebensdauern haben. Aber wir können nur die Referenz zurückgeben, deren Lebensdauer mit der im Rückgabetyp versprochenen übereinstimmt.

\n\n

Regel Nr. 3: Auch Strukturen können Referenzen speichern

\n\n

Wenn Sie eine Struktur erstellen, die Referenzen enthält, müssen Lebensdauern in Rust zwingend angegeben werden:

\n\n
struct Book<'a> {\n    title: &'a str,\n    author: &'a str,\n}\n\nfn main() {\n    let title = String::from("Rust Book");\n    let book;\n    {\n        let author = String::from("John Doe");\n        book = Book { title: &title, author: &author };\n    } // author wird hier zerstört!\n    println!("{}", book.title); // Fehler! book.author hängt\n}
\n\n

Der Compiler lässt diesen Code nicht kompilieren, weil book.author auf einen bereits gelöschten String verweist. Explizite Lifetimes in Rust ermöglichen es, solche Fehler zur Kompilierzeit abzufangen, nicht zur Laufzeit.

\n\n

Regel Nr. 4: Lifetime Elision – wann man sie nicht schreiben muss

\n\n

Rust ist klug genug, um Lebensdauern in einfachen Fällen selbst abzuleiten. Hier kann man auf die Angabe verzichten:

\n\n
    \n
  • Eine Eingangsreferenz – die Lebensdauer der Ausgabe ist gleich der

Blogs

Buchempfehlungen