Tempos de vida (Lifetimes) em Chamadas de Função

Além de emprestar seus argumentos, uma função pode retornar um valor emprestado:

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

fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a 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: &Point = left_most(&p1, &p2);
    println!("Ponto mais à esquerda: {:?}", p3);
}
  • 'a é um parâmetro genérico, ele é inferido pelo compilador.
  • Os tempos de vida começam com ' e 'a é um name padrão típico.
  • Leia &'a Point como “um Point emprestado que é válido por pelo menos o tempo de vida a”.
    • A parte pelo menos é importante quando os parâmetros estão em escopos diferentes.

No exemplo acima, tente o seguinte:

  • Mova a declaração de p2 e p3 para um novo escopo ({ ... }), resultando no seguinte código:

    #[derive(Debug)]
    struct Point(i32, i32);
    
    fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {
        if p1.0 < p2.0 { p1 } else { p2 }
    }
    
    fn main() {
        let p1: Point = Point(10, 10);
        let p3: &Point;
        {
            let p2: Point = Point(20, 20);
            p3 = left_most(&p1, &p2);
        }
        println!("Ponto mais à esquerda: {:?}", p3);
    }

    Note como isto não compila uma vez que p3 vive mais que p2.

  • Reinicie o espaço de trabalho e altere a assinatura da função para fn left_most<'a, 'b>(p1: &'a Point, p2: &'a Point) -> &'b Point. Isso não será compilado porque a relação entre os tempos de vida 'a e 'b não é clara.

  • Outra forma de explicar:

    • Duas referências a dois valores são emprestadas por uma função e a função retorna outra referência.
    • Ela deve ter vindo de uma dessas duas entradas (ou de uma variável global).
    • De qual? O compilador precisa saber, de forma que no local da chamada a referência retornada não seja usada por mais tempo do que uma variável de onde veio a referência.