Lezioni del modulo (1/2)
Lifetimes e riferimenti
In Rust, ogni riferimento ha un lifetime (durata), che corrisponde all'ambito (scope) all'interno del quale quel riferimento è valido. La maggior parte delle volte i lifetime sono impliciti e dedotti dal compilatore grazie alle regole di elisione. Tuttavia, quando la relazione tra i lifetime di diversi riferimenti è ambigua, dobbiamo annotarli esplicitamente.
L'obiettivo principale dei lifetime è prevenire i dangling references (riferimenti a dati che sono già stati deallocati dalla memoria).
La Sintassi delle Annotazioni dei Lifetime
I nomi dei lifetime iniziano con un apostrofo (') e sono solitamente scritti in lettere minuscole molto brevi (come 'a). Le annotazioni dei lifetime non cambiano la durata effettiva delle variabili, ma indicano al compilatore la relazione di validità tra i riferimenti ricevuti ed eventualmente restituiti.
Ad esempio, se una funzione prende due parametri che sono riferimenti a stringa e restituisce un riferimento a stringa, e vogliamo che il riferimento restituito sia valido finché entrambi i parametri in input sono validi, usiamo:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
Lifetime nelle Strutture dati
Se una struttura dati contiene un campo che è un riferimento, dobbiamo annotare esplicitamente il lifetime su quel riferimento per garantire che l'istanza della struct non possa sopravvivere al dato a cui si riferisce:
struct ImportantExcerpt<'a> {
part: &'a str,
}
fn main() {
let novel = String::from("Chiamami Ismaele. Alcuni anni fa...");
let first_sentence = novel.split('.').next().unwrap();
let i = ImportantExcerpt {
part: first_sentence,
};
}
Il Lifetime Statico
Il lifetime 'static è un lifetime speciale che dura per l'intera durata dell'esecuzione del programma. Tutti i letterali stringa (&str) hanno implicitamente un lifetime 'static perché sono codificati direttamente all'interno dell'eseguibile binario.
let s: &'static str = "Ho un lifetime statico.";
Prova tu
Esercizio 1: La funzione longest
Scrivi una funzione chiamata longest<'a> che accetta due parametri, x di tipo &'a str e y di tipo &'a str, e restituisce un valore di tipo &'a str. All'interno della funzione, usa un costrutto if/else per restituire il parametro x se la sua lunghezza è maggiore di y, altrimenti restituisci y.
Mostra suggerimento
Dichiara la firma con `fn longest<'a>(x: &'a str, y: &'a str) -> &'a str`. Poi usa `if x.len() > y.len() { x } else { y }`.
Soluzione disponibile dopo 3 tentativi
Esercizio 2: Strutture con riferimenti
Definisci una struttura chiamata Excerpt<'a> contenente un singolo campo chiamato part di tipo &'a str. Nel main, crea una variabile stringa chiamata text ed istanzia una variabile excerpt di tipo Excerpt prestando un riferimento a text. Stampa a schermo excerpt.part.
Mostra suggerimento
Usa `struct Excerpt<'a> { part: &'a str }`. Nel main istanziala con `Excerpt { part: &text }`.
Soluzione disponibile dopo 3 tentativi
Esercizio 3: Riferimenti statici
Dichiara una variabile chiamata message con annotazione di tipo esplicita per il lifetime statico (&'static str), assegnandole un valore letterale stringa. Stampa a schermo il valore di message.
Mostra suggerimento
Usa la sintassi `let message: &'static str = 'Messaggio statico!';` per annotare esplicitamente il lifetime statico.
Soluzione disponibile dopo 3 tentativi