Lecciones del módulo (1/2)
Lifetimes y referencias
En Rust, cada referencia tiene un lifetime (duración), que corresponde al ámbito (scope) dentro del cual esa referencia es válida. La mayoría de las veces los lifetimes son implícitos y deducidos por el compilador gracias a las reglas de elisión. Sin embargo, cuando la relación entre los lifetimes de diferentes referencias es ambigua, debemos anotarlos explícitamente.
El objetivo principal de los lifetimes es prevenir las dangling references (referencias a datos que ya han sido liberados de la memoria).
La Sintaxis de las Anotaciones de Lifetimes
Los nombres de los lifetimes comienzan con un apóstrofo (') y suelen escribirse con letras minúsculas muy cortas (como 'a). Las anotaciones de lifetimes no cambian la duración real de las variables, sino que indican al compilador la relación de validez entre las referencias recibidas y las devueltas eventualmente.
Por ejemplo, si una función toma dos parámetros que son referencias a cadena y devuelve una referencia a cadena, y queremos que la referencia devuelta sea válida mientras ambos parámetros de entrada sean válidos, usamos:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
Lifetimes en las Estructuras de datos
Si una estructura de datos contiene un campo que es una referencia, debemos anotar explícitamente el lifetime en esa referencia para garantizar que la instancia de la struct no pueda sobrevivir a los datos a los que se refiere:
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,
};
}
El Lifetime Estático
El lifetime 'static es un lifetime especial que dura toda la duración de la ejecución del programa. Todos los literales de cadena (&str) tienen implícitamente un lifetime 'static porque se codifican directamente dentro del ejecutable binario.
let s: &'static str = "Ho un lifetime statico.";
Pruébalo tú
Ejercicio 1: La función longest
Escribe una función llamada longest<'a> que acepte dos parámetros, x de tipo &'a str e y de tipo &'a str, y devuelva un valor de tipo &'a str. Dentro de la función, usa un constructor if/else para devolver el parámetro x si su longitud es mayor que la de y; de lo contrario, devuelve y.
Mostrar pista
Declara la firma con `fn longest<'a>(x: &'a str, y: &'a str) -> &'a str`. Luego usa `if x.len() > y.len() { x } else { y }`.
Solución disponible después de 3 intentos
Ejercicio 2: Estructuras con referencias
Define una estructura llamada Excerpt<'a> que contenga un solo campo llamado part de tipo &'a str. En el main, crea una variable de cadena llamada text e instancia una variable excerpt de tipo Excerpt prestando una referencia a text. Imprime en pantalla excerpt.part.
Mostrar pista
Usa `struct Excerpt<'a> { part: &'a str }`. En el main instánciala con `Excerpt { part: &text }`.
Solución disponible después de 3 intentos
Ejercicio 3: Referencias estáticas
Declara una variable llamada message con anotación de tipo explícita para el lifetime estático (&'static str), asignándole un valor literal de cadena. Imprime en pantalla el valor de message.
Mostrar pista
Usa la sintaxis `let message: &'static str = 'Messaggio statico!';` para anotar explícitamente el lifetime estático.
Solución disponible después de 3 intentos