E0621: Conflito de Lifetimes
O erro E0621 ocorre quando há um conflito entre os lifetimes esperados e os lifetimes fornecidos em parâmetros de função. Geralmente acontece quando o tipo de retorno exige um lifetime específico, mas o corpo da função retorna algo com um lifetime diferente.
A Mensagem de Erro
error[E0621]: explicit lifetime required in the type of `y`
--> src/main.rs:4:5
|
1 | fn escolher<'a>(x: &'a str, y: &str) -> &'a str {
| ---- help: add explicit lifetime `'a` to the type of `y`: `&'a str`
...
4 | y
| ^ lifetime `'a` required
Outra variação:
error: lifetime may not live long enough
--> src/main.rs:3:5
|
1 | fn exemplo<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
3 | y
| ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
O Que Significa
Quando você anota lifetimes em uma função, está criando um contrato: “o valor retornado será válido pelo tempo X”. Se o corpo da função retorna algo com um lifetime diferente (mais curto, por exemplo), o contrato é violado.
No primeiro exemplo, a função declara que retorna &'a str, vinculado ao lifetime de x. Mas o corpo retorna y, que tem um lifetime diferente e potencialmente mais curto. O compilador não pode garantir que y viverá tanto quanto 'a, então rejeita o código.
Isso também acontece quando os lifetimes são nomeados separadamente ('a e 'b) mas o retorno exige um deles — e o outro é retornado.
Código com Erro
// O retorno está vinculado a 'a (lifetime de `x`)
// mas a função pode retornar `y`, que tem lifetime diferente
fn escolher<'a>(x: &'a str, y: &str) -> &'a str {
if x.len() > 5 {
x
} else {
y // ERRO: `y` não tem lifetime 'a
}
}
Com lifetimes separados:
fn primeiro<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
if x.is_empty() {
y // ERRO: retorna 'b mas assinatura promete 'a
} else {
x
}
}
Em métodos de struct:
struct Buffer<'a> {
dados: &'a str,
}
impl<'a> Buffer<'a> {
fn combinar(&self, outro: &str) -> &'a str {
if self.dados.is_empty() {
outro // ERRO: `outro` não tem lifetime 'a
} else {
self.dados
}
}
}
Como Resolver
Solução 1: Unificar os Lifetimes
Se ambos os parâmetros podem ser retornados, dê a eles o mesmo lifetime:
fn escolher<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > 5 {
x
} else {
y
}
}
fn main() {
let a = String::from("Rust Brasil");
let b = String::from("Olá");
let resultado = escolher(&a, &b);
println!("{}", resultado);
}
Quando ambos os parâmetros têm lifetime 'a, o compilador usa o menor dos dois lifetimes. Isso garante que o retorno é válido enquanto ambas as entradas são válidas.
Solução 2: Adicionar Lifetime ao Parâmetro Faltante
Se o compilador sugere adicionar lifetime a um parâmetro, siga a sugestão:
// Antes (erro):
fn escolher<'a>(x: &'a str, y: &str) -> &'a str { ... }
// Depois (correto):
fn escolher<'a>(x: &'a str, y: &'a str) -> &'a str { ... }
Solução 3: Usar Bound de Lifetime ('b: 'a)
Se você precisa de lifetimes separados mas quer garantir que um vive pelo menos tanto quanto o outro:
fn escolher<'a, 'b: 'a>(x: &'a str, y: &'b str) -> &'a str {
if x.len() > 5 {
x
} else {
y // OK: 'b vive pelo menos tanto quanto 'a
}
}
O 'b: 'a lê-se como “‘b vive pelo menos tanto quanto ‘a” (outlives). Isso garante que é seguro retornar y onde 'a é esperado.
Solução 4: Retornar Tipo Owned
Se a complexidade de lifetimes estiver alta, retorne um valor owned:
fn escolher(x: &str, y: &str) -> String {
if x.len() > 5 {
x.to_string()
} else {
y.to_string()
}
}
Isso elimina completamente o problema de lifetime, ao custo de uma alocação.
Solução 5: Corrigir a Lógica do Retorno
Às vezes o conflito indica um bug lógico — a função deveria retornar apenas do parâmetro correto:
fn prefixo<'a>(texto: &'a str, _config: &str) -> &'a str {
// Retorna sempre do parâmetro com lifetime 'a
&texto[..3]
}
Entendendo Lifetime Bounds
| Sintaxe | Significado |
|---|---|
'a | Um lifetime genérico |
'b: 'a | 'b vive pelo menos tanto quanto 'a |
T: 'a | O tipo T e todas suas referências vivem pelo menos tanto quanto 'a |
'static | Vive durante toda a execução do programa |