Anotações de Tempo de Vida

Uma referência tem um tempo de vida (lifetime), que não deve "sobreviver" ao valor ao qual se refere. Isso é verificado pelo borrow checker (verificador de empréstimo).

O tempo de vida pode ser implícito - isso é o que vimos até agora. Os tempos de vida também podem ser explícitos: &'a Point, &'document str. Os tempos de vida começam com ' e 'a é um nome padrão típico. Leia &'a Point como "um Point emprestado que é válido por pelo menos o tempo de vida a".

Os tempos de vida são sempre inferidos pelo compilador: você não pode atribuir um tempo de vida por conta própria. Anotações explícitas de tempo de vida criam restrições onde há ambiguidade; o compilador verifica se há uma solução válida.

Os tempos de vida se tornam mais complicados ao considerar a passagem de valores para e a devolução de valores de funções.

#[derive(Debug)]
struct Point(i32, i32);

fn left_most(p1: &Point, p2: &Point) -> &Point {
    if p1.0 < p2.0 {
        p1
    } else {
        p2
    }
}

fn main() {
    let p1: Point = Point(10, 10);
    let p2: Point = Point(20, 20);
    let p3 = left_most(&p1, &p2); // Qual é o tempo de vida de p3?
    println!("p3: {p3:?}");
}
This slide should take about 10 minutes.

Neste exemplo, o compilador não sabe qual tempo de vida inferir para p3. Olhando dentro do corpo da função nos mostra que ele só pode assumir com segurança que o tempo de vida de p3 é o mais curto de p1 e p2. Mas assim como os tipos, o Rust requer anotações explícitas de tempos de vida nos argumentos e valores de retorno da função.

Adicione 'a apropriadamente a left_most (mais à esquerda):

fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {

Isto diz, "dado p1 e p2 que sobrevivem a 'a, o valor de retorno vive por pelo menos 'a.

Em casos comuns, os tempos de vida podem ser omitidos, como descrito no próximo slide.