E0621: Conflito de Lifetimes no Rust

Como resolver o erro E0621 do Rust: conflito entre lifetimes em parâmetros de função. Aprenda a alinhar anotações de lifetime e corrigir incompatibilidades.

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

SintaxeSignificado
'aUm lifetime genérico
'b: 'a'b vive pelo menos tanto quanto 'a
T: 'aO tipo T e todas suas referências vivem pelo menos tanto quanto 'a
'staticVive durante toda a execução do programa

Veja Também