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 →