Aprende Rust · Guía 4 de 8 · 3 min
Lifetimes: cuánto vive una referencia
Qué significa 'a, por qué casi nunca hay que escribirlo y cómo resolver los errores más comunes.
El problema que resuelven
Aquí r intenta seguir usándose cuando s ya no existe:
fn main() {
let r;
{
let s = String::from("hola");
r = &s;
} // `s` se libera aquí
println!("{r}"); // error[E0597]: `s` does not live long enough
}
En C, un error así puede compilar y convertirse en un fallo de seguridad. En Rust, no pasa del compilador.
La buena noticia: casi nunca los escribes
Rust deduce la mayoría de los lifetimes por ti. Esta función no necesita ninguna anotación, porque solo hay una entrada posible para la salida:
fn primera_palabra(texto: &str) -> &str {
texto.split(' ').next().unwrap_or("")
}
fn main() {
println!("{}", primera_palabra("hola mundo"));
}
Cuándo sí hay que escribirlos
Con dos referencias de entrada, Rust no puede adivinar de cuál depende el resultado:
fn mas_largo(a: &str, b: &str) -> &str { // error[E0106]
if a.len() > b.len() { a } else { b }
}
La solución es ponerle nombre a esa relación:
fn mas_largo<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() { a } else { b }
}
fn main() {
let a = String::from("Arequipa");
let b = String::from("Lima");
println!("{}", mas_largo(&a, &b));
}
Se lee así: el resultado es válido mientras a y b sean válidos.
Lo que el compilador protege
Con esa firma, Rust detecta un uso peligroso, aunque aquí el texto más largo sea a. El error dice que b no vive lo suficiente:
fn mas_largo<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() > b.len() { a } else { b }
}
fn main() {
let a = String::from("Arequipa");
let r;
{
let b = String::from("Lima");
r = mas_largo(&a, &b); // error[E0597]
}
println!("{r}");
}
En structs
Si un struct guarda una referencia, debe declarar que no puede vivir más que ese dato:
struct Extracto<'a> {
texto: &'a str,
}
fn main() {
let libro = String::from("Había una vez. Fin.");
let primera = libro.split('.').next().unwrap();
let cita = Extracto { texto: primera };
println!("{}", cita.texto);
}
'static: vive todo el programa
Los textos literales están dentro del ejecutable, así que su lifetime es 'static:
fn main() {
let saludo: &'static str = "Hola";
println!("{saludo}");
}
Si el compilador te sugiere 'static, desconfía: rara vez es la solución correcta para un dato que creaste en tiempo de ejecución.
Qué hacer cuando el compilador se queja
Prueba en este orden:
- Devuelve un valor propio. Un
Stringen lugar de un&strelimina el problema. - Declara el dato en un alcance más amplio. Así vive más que la referencia.
- Usa
.clone(). Mientras aprendes, es una salida válida.