← Rust EspañolChapter 11 of 13

Tiempos de Vida

## Objetivos de Aprendizaje - Comprender que son los tiempos de vida - Aprender las anotaciones de tiempo de vida - Dominar las reglas de eliminacion - Usar el tiempo de vida 'static - Evitar referencias colgantes ## Que son los Tiempos de Vida? Los tiempos de vida aseguran que las referencias siempre sean validas. El compilador verifica que las referencias no sobrevivan a los datos a los que referencian. ```rust fn main() { let r; { let x = 5; r = &x; // Error: x no vive lo suficiente } println!("{}", r); } ``` ## Anotaciones de Tiempo de Vida ### Sintaxis ```rust &'a type // Referencia con tiempo de vida 'a &'a mut type // Referencia mutable con tiempo de vida 'a ``` ### Tiempos de Vida Nombrados ```rust fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } fn main() { let s1 = String::from("long string"); let result; { let s2 = String::from("xyz"); result = longest(s1.as_str(), s2.as_str()); println!("{}", result); } // result seria invalido aqui si se usara } ``` ## Eliminacion de Tiempos de Vida El compilador infiere tiempos de vida en casos comunes. ### Reglas de Eliminacion 1. Cada parametro de referencia obtiene su propio tiempo de vida 2. Si hay exactamente un tiempo de vida de entrada, se asigna a la salida 3. Si hay un `&self` o `&mut self`, se asigna a la salida ### Ejemplos ```rust // Regla 1: Cada parametro obtiene un tiempo de vida fn foo(x: &str, y: &str) -> &str { } // Compilador ve: foo<'a, 'b>(x: &'a str, y: &'b str) -> &str // Regla 2: Un solo tiempo de vida de entrada -> salida fn first_word(s: &str) -> &str { } // Compilador ve: first_word<'a>(s: &'a str) -> &'a str // Regla 3: &self -> tiempo de vida de salida impl Config { fn get_name(&self) -> &str { } // Compilador ve: get_name<'a>(&'a self) -> &'a str } ``` ### Cuando la Eliminacion No Funciona ```rust // Error: referencia de retorno con tiempo de vida poco claro fn longest(x: &str, y: &str) -> &str { // Error del compilador! if x.len() > y.len() { x } else { y } } // Solucion: agregar tiempo de vida explicito fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } ``` ## Structs con Referencias Los structs que hold referencias necesitan anotaciones de tiempo de vida: ```rust struct ImportantExcerpt<'a> { part: &'a str, } fn main() { let novel = String::from("Call me Ishmael..."); let first_sentence = novel.split('.').next().unwrap(); let excerpt = ImportantExcerpt { part: first_sentence, }; } ``` ### Metodos con Tiempos de Vida ```rust impl<'a> ImportantExcerpt<'a> { fn level(&self) -> i32 { 3 } fn announce_and_return(&self, announcement: &str) -> &str { println!("Attention: {}", announcement); self.part } } ``` ## Tiempo de Vida Estatico `'static` significa que la referencia vive durante todo el programa: ```rust let s: &'static str = "I live forever"; fn main() { // Los literales de string tienen tiempo de vida 'static let s = "hello"; // &'static str // Las referencias &'static pueden sobrevivir a cualquier dato } ``` ### Cuando Usar 'static ```rust // Mensajes de error fn generic() { } // T: 'static a veces necesario // Constantes globales const GREETING: &str = "Hello"; // &'static // Box con datos estaticos fn get_static_string() -> &'static str { "a static string" } ``` ## Subtipo de Tiempo de Vida Un tiempo de vida sobrevive a otro: ```rust struct Context<'a, 'b> { part: &'a str, other: &'b str, } fn main() { let s1 = String::from("long string"); let s2 = String::from("short"); { let excerpt = Context { part: s1.as_str(), other: s2.as_str(), }; } // excerpt se descarta aqui } ``` ## Multiples Tiempos de Vida ```rust fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { if x.len() > y.len() { x } else { x // Devolver 'a de todos modos (podria devolver y con &'b) } } ``` ## Tiempo de Vida en Metodos ```rust struct Owner(i32); impl Owner { fn add_one<'a>(&'a mut self) { self.0 += 1; } fn print<'a>(&'a self) { println!("{}", self.0); } } fn main() { let mut owner = Owner(10); owner.add_one(); owner.print(); } ``` ## Limites de Traits con Tiempos de Vida ```rust use std::fmt::Display; fn longest_with_anouncement<'a, T> where T: 'a, T: Display, { // ... } ``` ## Patrones Comunes ### Referencia en Struct ```rust struct Ref<'a, T> { data: &'a T, } fn main() { let x = 5; let r = Ref { data: &x }; println!("{:?}", r.data); } ``` ### Multiples Referencias ```rust struct MultiRef<'a, 'b, 'c, T> { first: &'a T, second: &'b T, third: &'c T, } ``` ## Resumen - Los tiempos de vida previenen referencias colgantes - Anotaciones: `&'a T` significa referencia vive al menos 'a - Las reglas de eliminacion manejan casos comunes automaticamente - Los structs con referencias necesitan parametros de tiempo de vida - `'static` significa referencia vive durante todo el programa - Multiples tiempos de vida cuando es necesario - Los metodos usan sintaxis `impl<'a>` - Limites de tiempo de vida: `T: 'a`

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →