In Rust wurde aufgrund des strengen Speichermanagements ein Mechanismus für Lebensdauern (lifetimes) eingeführt, der es dem Compiler ermöglicht, die Gültigkeit von Referenzen zu überprüfen. Das manuelle Angeben von Lebensdauer-Anmerkungen wäre jedoch mühsam, weshalb im Sprachkonzept Regeln zur "Elision" eingeführt wurden, die es dem Compiler in bestimmten Fällen ermöglichen, die Lebensdauer automatisch abzuleiten.
Ohne korrektes Management der Lebensdauer von Referenzen können Fehler wie hängende Zeiger (dangling pointers) oder Datenrennen auftreten. Wenn Programmierer immer gezwungen wären, Lebensdauern explizit anzugeben, würde das die Entwicklung erheblich erschweren.
Der Rust-Compiler verwendet die Regeln der Lebensdauerelision, um in häufigen Funktionssiganturen automatisch zu bestimmen, welche Lebensdauern zwischen den Eingabereferenzen und den zurückgegebenen Werten verknüpft werden sollten. Dies reduziert die Menge des Boilerplate-Codes und macht die API verständlicher, während die Sicherheit gewahrt bleibt.
Codebeispiel:
fn get_first(s: &str) -> &str { // Lebensdauerelision &s[..1] }
Hier leitet der Compiler die Lebensdauer des Ergebnisses ab — sie entspricht der Lebensdauer des Eingabeparameters s.
Wichtige Merkmale:
Warum kann man Lebensdauern nicht immer weglassen und sich auf die Regeln der Elision verlassen?
Die Elision funktioniert nur in "einfachen" Situationen. Zum Beispiel, wenn eine Funktion eine der Eingabereferenzen zurückgibt, kann der Compiler deren Lebensdauern verknüpfen, aber wenn es mehrere nicht offensichtliche Verknüpfungen gibt — tritt ein Kompilierfehler auf und es müssen alles explizit annotiert werden.
fn pick<'a>(a: &'a str, b: &'a str, first: bool) -> &'a str { if first { a } else { b } } // Hier muss 'a explizit angegeben werden, sonst kann der Compiler die Verknüpfung nicht verstehen.
Kann man die Lebensdauer einer Struktur weglassen, wenn sie nur Referenzfelder enthält?
Nein, wenn eine Struktur Referenzfelder enthält, muss sie ein Lebensdauern-Parameter haben, um sicherzustellen, dass die Instanz der Struktur ihre Daten nicht überlebt.
struct Foo<'a> { data: &'a str, }
Was passiert, wenn man versucht, eine Referenz auf eine lokale Variable zurückzugeben?
Der Compiler gibt einen Fehler aus, auch wenn formal die Regeln der Elision eine Lebensdauer "ableiten" könnten. Rust verfolgt die Lebensdauer nicht nur nach Typ, sondern auch nach Sichtbarkeitsbereich.
Ein Programmierer hat eine API geschrieben, in der er die Lebensdauer, die eine Referenz auf einen lokalen temporären Puffer innerhalb einer Funktion zurückgibt, nicht explizit angegeben hat. Der Compiler hat den Code abgelehnt, aber beim Versuch, den Fehler zu "umgehen", wurden falsche Lebensdauer-Anmerkungen hinzugefügt, was zu mehreren verwirrenden Fehlern führte.
Vorteile:
Nachteile:
In der API der Bibliothek werden korrekte Lebensdauer-Anmerkungen nur dort verwendet, wo sie tatsächlich benötigt werden. Alles andere wird durch die automatischen Regeln der Elision abgedeckt, was den Code knackig und verständlich macht.
Vorteile:
Nachteile: