Rust-Lifetimes
Der Rust-Lebensdauer-Mechanismus ist ein ebenso wichtiger Ressourcenverwaltungsmechanismus wie der Ownership-Mechanismus.
Der Hauptgrund für die Einführung dieses Konzepts ist der Umgang mit Ressourcenverwaltungsproblemen in komplexen Typsystemen.
Referenzen sind ein wesentlicher Mechanismus im Umgang mit komplexen Typen; schließlich können Daten komplexer Typen nicht einfach vom Prozessor kopiert und berechnet werden.
Aber Referenzen führen oft zu äußerst komplexen Ressourcenverwaltungsproblemen. Betrachten wir zunächst Dangling-Referenzen:
Beispiel
let r;
{
let x = 5;
r = &x;
}
println!("r: {}", r);
}
Dieser Code wird vom Rust-Compiler nicht akzeptiert, weil der von r referenzierte Wert bereits verworfen wurde, bevor er verwendet wird.

In der obigen Abbildung stellt der grüne Bereich 'a die Lebensdauer von r dar und der blaue Bereich 'b die Lebensdauer von x. Offensichtlich ist 'b viel kürzer als 'a; eine Referenz muss innerhalb der Lebensdauer des Werts liegen, um gültig zu sein.
Wir haben in Structs immer String statt &str verwendet. Erklären wir anhand eines Beispiels, warum:
Beispiel
if s2.len() > s1.len() {
s2
} else {
s1
}
}
Die Funktion longer nimmt zwei String-Slices, s1 und s2, entgegen und gibt die Referenz auf den längeren zurück. Dieser Code wird jedoch nicht kompiliert, da die zurückgegebene Referenz eine hängende Referenz sein könnte:
Beispiel
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
}
println!("{} is longer", r);
}
In diesem Programm wurde zwar ein Vergleich durchgeführt, doch bis r verwendet wird, sind die Quellwerte s1 und s2 bereits ungültig geworden. Natürlich könnten wir die Verwendung von r in den Lebensdauerbereich von s1 und s2 verschieben, um diesen Fehler zu verhindern, aber die Funktion kann nicht wissen, was außerhalb von ihr geschieht. Um sicherzustellen, dass der von ihr ausgegebene Wert gültig ist, muss sie dem Ownership-Prinzip folgen, um alle Gefahren auszuschließen, daher kann die Funktion longer nicht kompiliert werden.
Lebensdauer-Annotation
Eine Lebensdauer-Annotation ist eine Möglichkeit, die Lebensdauer von Referenzen zu beschreiben.
Obwohl dies die Lebensdauer von Referenzen nicht ändern kann, kann es an geeigneten Stellen deklarieren, dass die Lebensdauern zweier Referenzen übereinstimmen.
Eine Lebensdauer-Annotation beginnt mit einem Apostroph, auf den ein kleingeschriebenes Wort folgt:
&i32 // 常规引用 &'a i32 // 含有生命周期注释的引用 &'a mut i32 // 可变型含有生命周期注释的引用
Lass uns die Funktion longer mit Lifetime-Annotationen refaktorisieren:
Beispiel
if s2.len() > s1.len() {
s2
} else {
s1
}
}
Wir müssen generische Deklarationen verwenden, um die Lifetime-Namen anzugeben; dann stimmt die Lifetime des Rückgabewerts der Funktion mit den Lifetimes der beiden Parameter überein, sodass wir beim Aufruf schreiben können:
Beispiel
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
println!("{} is longer", r);
}
}
Die kombinierte Ausgabe der beiden obigen Programme:
ecmascript is longer
Hinweis:Vergiss nicht das Prinzip der automatischen Typinferenz.
Verwendung von String-Slice-Referenzen in Structs
Dies ist die zuvor offen gelassene Frage; hier ist die Antwort:
Beispiel
struct Str<'a> {
content: &'a str
}
let s = Str {
content: "string_slice"
};
println!("s.content = {}", s.content);
}
Ausgabe:
s.content = string_slice
Wenn es eine Methodendefinition für das struct Str gibt:
Beispiel
fn get_content(&self) -> &str {
self.content
}
}
Der Rückgabewert hat hier keine Lebensdauer-Annotation, aber eine hinzuzufügen schadet nicht. Dies ist ein historisches Problem: Frühes Rust unterstützte keine automatische Lebensdauer-Inferenz, und alle Lebensdauern mussten strikt deklariert werden, aber gängige stabile Versionen von Rust unterstützen diese Funktion bereits.
Statische Lebensdauer
Es gibt eine spezielle Lebensdauer-Annotation: 'static. Der genaue Datentyp, der von allen in doppelte Anführungszeichen eingeschlossenen String-Konstanten repräsentiert wird, ist &'static str; die durch 'static bezeichnete Lebensdauer reicht vom Beginn der Programmausführung bis zum Ende der Programmausführung.
Generika, Traits und Lebensdauern im Zusammenspiel
Beispiel
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
where T: Display
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
Dieses Programm stammt aus der Rust-Bibel (Rust Book). Es ist ein Programm, das gleichzeitig Generics, Traits und Lifetime-Mechanismen verwendet. Es ist nicht zwingend erforderlich; du kannst es ausprobieren, schließlich wirst du es früher oder später brauchen!
Andere Erweiterungen