Pentru mulți dezvoltatori aflați la început de drum, Lifetimes (duratele de viață) reprezintă conceptul cel mai intimidant din Rust. În esență, un lifetime (notat sintactic cu apostrof, ex: 'a) nu este o instrucțiune de runtime, ci un parametru de tip generic pentru compilator care descrie relația de longevitate dintre două sau mai multe referințe din memorie.
Evoluția compilatorului rustc a trecut printr-un salt major odată cu Non-Lexical Lifetimes (NLL): duratele de viață nu mai sunt legate mecanic de acoladele blocului de cod ({}), ci se termină exact în punctul unde referința a fost citită ultima oară.
use std::collections::HashMap;
// Într-un analizator tradițional de împrumuturi, următorul cod genera o eroare fals-pozitivă:
fn obtine_sau_adauga<'a>(harta: &'a mut HashMap, cheie: &str) -> &'a String {
// 1. Împrumutăm imutabil pentru verificare:
if let Some(valoare) = harta.get(cheie) {
return valoare; // Împrumutul ar trebui să se termine aici dacă nu găsim!
}
// 2. În NLL vechi, împrumutul imutabil 'valoare' era considerat activ pe întreg corpul funcției,
// blocând apelul mutabil 'insert' de mai jos!
harta.insert(cheie.to_string(), String::from("implicit"));
&harta[cheie]
}
Noul Model Polonius: Împrumuturi pe Bază de Origine
Echipa Rust a reproiectat nucleul Borrow Checker-ului într-un nou analizator formal denumit Polonius. Spre deosebire de NLL (care calculează duratele de viață pe baza seturilor de puncte de control din graful CFG), Polonius urmărește originile datelor (Origins and Loans):
- Polonius înțelege că dacă o ramură
ifa returnat devreme valoarea, împrumutul este complet retras pe ramuraelse, permițând mutația imediată a aceleiași structuri fără erori de compilare. - Elimină necesitatea unor artificii precum
harta.entry(cheie).or_insert(...)în scenariile în care căutarea inițială este mult mai ieftină decât construirea unuiEntry.
Varianța Duratelor de Viață (Subtyping & Variance)
| Tip de Relație | Varianță în Rust | Explicație Matematică |
|---|---|---|
&'a T |
Covariant pe 'a și T |
Dacă 'static este mai lung decât 'a, putem pasa un &'static T acolo unde se cere un &'a T. |
&'a mut T |
Covariant pe 'a, dar Invariant pe T! |
Nu putem pasa un &mut &'static str unde se cere &mut &'a str, altfel am putea scrie un șir cu viață scurtă într-o referință statică! |