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 “umPoint
emprestado que é válido por pelo menos o tempo de vidaa
”.- 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
ep3
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 quep2
. -
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.