ProgrammierungRust-Entwickler

Was sind Lifetimes in Rust und warum sind sie beim Arbeiten mit Referenzen nötig?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

In Rust definieren Lifetimes den Gültigkeitsbereich von Referenzen, damit der Compiler sicherstellen kann, dass Zeiger nicht im Leeren hängen (keine hängenden Referenzen vorhanden sind). Dies ermöglicht eine Speichersicherheit zur Compile-Zeit ohne die Notwendigkeit eines Garbage Collectors.

Wenn Sie mit Referenzen arbeiten, verlangt Rust, dass Sie deren Lebensdauer explizit angeben, wenn der Compiler dies nicht selbst ableiten kann. Dies geschieht normalerweise mit der Syntax 'a:

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

Hier haben beide Parameter und der Rückgabewert dieselbe Lifetime, was garantiert: die zurückgegebene Referenz lebt nicht länger als einer der Argumente.

Lifetimes ändern nicht die Lebensdauer der Daten, sondern beschreiben sie nur dem Compiler.

Fangfrage

Kann man eine Referenz auf eine lokale Variable innerhalb einer Funktion zurückgeben?

Nein, kann man nicht: da eine solche Variable beim Verlassen der Funktion zerstört wird. Beispiel:

fn foo() -> &String { // Kompilierungsfehler! let s = String::from("hello"); &s } // Referenz auf s wird ungültig

Der Compiler wird diesen Code nicht kompilieren: Er schützt Sie davor, Referenzen auf zerstörte Daten zu verwenden.

Beispiele für reale Fehler aufgrund von Unkenntnis der Feinheiten des Themas


Geschichte

Im Team gab es viele Speicherlecks, als Funktionen versehentlich Referenzen auf lokale Puffer zurückgaben. Das funktionierte nicht, und nur der Compiler, der mit Lifetimes zu meckern begann, wurde zu Hilfe gerufen. Aufgrund des häufigen Auftretens solcher Fehler wurde die Regel eingeführt, die Lifetime explizit anzugeben, wenn eine Funktion mit komplexen Strukturen mit verschachtelten Referenzen arbeitet.


Geschichte

Im Projekt wurde generischer Code zur Zwischenspeicherung von Daten geschrieben. Bei falscher Gestaltung der Lifetime-Generikparameter traten Fehler wie "cannot infer lifetime" auf, und es war unmöglich, die Lebensdauer von Daten im Cache abzuleiten. Dies führte dazu, dass Lifetime-Anmerkungen durch Ausprobieren angepasst wurden, bis die Entscheidung getroffen wurde, zwischengespeicherte und nicht zwischengespeicherte Daten in verschiedene Strukturen zu trennen.


Geschichte

Einer der Kollegen versuchte, einen Verbindungs-Pool unter Verwendung von Referenzen auf Verbindungsobjekte zu implementieren, berücksichtigte jedoch nicht, dass die Lifetimes der Verbindungen nicht mit der Lebensdauer des Pools übereinstimmten. Infolgedessen traten hängende Referenzen nach der Freigabe der Verbindungen auf, was erst während der umfassenden Testphase bemerkt wurde. Danach wechselte das Projekt zu sicheren Wrappern (Arc<Mutex<T>>).