W Rust lifetimes określają zakres widoczności referencji, aby kompilator mógł upewnić się, że wskaźniki nie są pozostawione w powietrzu (nie ma wiszących referencji). Pozwala to zapewnić bezpieczeństwo pamięci w czasie kompilacji bez potrzeby używania zbieracza śmieci.
Gdy pracujesz z referencjami, Rust wymaga wyraźnego określenia ich czasu życia, gdy kompilator nie może tego wydedukować samodzielnie. Zwykle robi się to za pomocą składni 'a:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
Tutaj oba parametry i wartość zwracana mają ten sam lifetime, co gwarantuje: zwracana referencja nie będzie żyła dłużej niż jakikolwiek z argumentów.
Lifetimes nie zmieniają czasu życia danych, a jedynie opisują go kompilatorowi.
Czy można zwrócić referencję na lokalną zmienną wewnątrz funkcji?
Nie, nie można: ponieważ taka zmienna zostanie zniszczona po wyjściu z funkcji. Przykład:
fn foo() -> &String { // błąd kompilacji! let s = String::from("hello"); &s } // referencja na s staje się nieważna
Kompilator nie pozwoli na skompilowanie takiego kodu: ochroni cię przed używaniem referencji na zniszczone dane.
Historia
W zespole pojawiło się wiele wycieków pamięci, gdy funkcje przypadkowo zwracały referencje na lokalne bufory. To nie zadziałało, a uratował nas tylko kompilator, który zaczął narzekać na lifetimes. Z powodu częstych wystąpień takich błędów przyjęto zasadę wyraźnego określania lifetime, jeśli funkcja pracuje złożonymi strukturami z zagnieżdżonymi referencjami.
Historia
W projekcie napisano kod generics do cache'owania danych. Przy niewłaściwym zaprojektowaniu parametry lifetimes generics pojawiały się błędy typu "cannot infer lifetime" i stało się niemożliwe wydedukowanie czasu życia danych przechowywanych w cache. Prowadziło to do dostosowywania adnotacji lifetime metodą prób i błędów, aż podjęto decyzję o podzieleniu danych cachowanych i niecachowanych na różne struktury.
Historia
Jeden z kolegów próbował zaimplementować pulę połączeń, używając referencji do obiektów połączeń, ale nie uwzględniał, że lifetimes połączeń nie pokrywają się z czasem życia puli. W rezultacie pojawiły się wiszące referencje po zwolnieniu połączeń, co zauważono dopiero na etapie kompleksowego testowania. Po tym projekcje przeszło na bezpieczne opakowania (Arc<Mutex<T>>).