Was verbirgt sich hinter einem einzelnen Anführungszeichen? Lernen wir Lifetimes in Rust kennen
Wenn Sie jemals Code in Rust geöffnet und seltsame Konstrukte wie &'a str oder fn foo<'a>() gesehen haben, haben Sie sich sicherlich gefragt: „Was sind das für Apostrophe?“. Sie sind nicht allein – diese Frage hat tausende Aufrufe auf Stack Overflow gesammelt und ist für Anfänger zu einem echten Kopfschmerz geworden.
Heute werden wir diese geheimnisvollen Symbole ein für alle Mal klären. Spoiler: Hinter den Anführungszeichen verbirgt sich eines der mächtigsten Konzepte von Rust – die Lebensdauer (Lifetime). Und ja, es ist nicht so beängstigend, wie es scheint!
In diesem Artikel erkläre ich nicht nur die Syntax, sondern auch, wie man Identifikatoren mit Apostroph richtig liest und verwendet. Los geht's!
Identifikatoren mit Apostroph: Nicht nur eine Verzierung
In Rust sind Identifikatoren, die mit einem einfachen Anführungszeichen beginnen (z.B. 'a, 'static, 'b), Lebensdauer-Annotationen. Sie beeinflussen nicht, wie lange eine Variable lebt, sondern teilen dem Compiler lediglich die Beziehungen zwischen den Lebensdauern verschiedener Referenzen mit.
Stellen Sie sich vor, Sie sind ein Detektiv und der Rust-Compiler Ihr Assistent. Sie sagen: „Diese beiden Referenzen müssen gleich lange leben“ und markieren sie mit dem Label 'a. Der Compiler überprüft, ob Sie diese Regel nicht verletzen. Wenn doch, erhalten Sie einen Fehler zur Kompilierzeit und nicht zur Laufzeit.
Warum sehen sie genau so aus?
Die Syntax mit Apostroph ist nicht zufällig gewählt. In Rust wird der Apostroph verwendet, um Labels (Markierungen) zu kennzeichnen – eine Art „Namen“ für Zeitabschnitte. Dieser Ansatz kommt auch in anderen Sprachen vor, aber in Rust wurde er zu einem Schlüsselelement des Speichersicherheitssystems.
Hier sind einige Beispiele, wo Sie diese Labels antreffen werden:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str– eine Funktion, die eine Referenz zurückgibt, die nicht länger lebt als beide Argumente.struct Book<'a> { title: &'a str }– eine Struktur, die eine Referenz mit einer Lebensdauer enthält.&'static str– eine Referenz auf einen statischen String, der während des gesamten Programms lebt.
Wie liest und versteht man Lifetimes?
Lassen Sie uns einige reale Codebeispiele durchgehen. Sie werden Ihnen helfen, keine Angst mehr vor Apostrophen zu haben und sie zu verwenden.
Beispiel 1: Funktion mit einer Lebensdauer
Angenommen, wir schreiben eine Funktion, die den längeren von zwei Strings zurückgibt:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}
fn main() { let string1 = String::from("hello"); let result; { let string2 = String::from("world"); result = longest(&string1, &string2); } // println!("{}", result); // Kompilierfehler!}Was passiert hier? Wir teilen dem Compiler mit: „Das Ergebnis wird nicht länger leben als x und y zusammen.“ Wenn string2 den Gültigkeitsbereich verlässt, wird result ungültig. Der Compiler sieht das und lässt uns nicht ins offene Messer laufen.
Beispiel 2: Struktur mit einer Referenz
Anfänger versuchen oft, Referenzen in Strukturen zu speichern und erhalten Fehler. Die Lösung besteht darin, die Lebensdauer explizit anzugeben:
#[derive(Debug)]struct Book<'a> { title: &'a str, author: &'a str,}
fn main() { let title = String::from("The Rust Programming Language"); let author = String::from("Steve Klabnik"); let book = Book { title: &title, author: &author, }; println!("{:?}", book);}Hier bedeutet 'a, dass title und author mindestens so lange leben müssen wie die Struktur Book selbst. Wenn Sie versuchen, sie zu löschen