E0597: Valor Não Vive Tempo Suficiente no Rust

Como resolver o erro E0597 do Rust: valor não vive tempo suficiente. Entenda por que referências são invalidadas quando valores saem de escopo e veja soluções.

E0597: Valor Não Vive Tempo Suficiente

O erro E0597 ocorre quando uma referência tenta sobreviver ao valor que ela referencia. Em outras palavras, o valor é destruído (dropped) antes que a referência que aponta para ele deixe de ser usada. Isso criaria uma dangling reference — uma referência para memória inválida.

A Mensagem de Erro

error[E0597]: `temporario` does not live long enough
 --> src/main.rs:4:19
  |
3 |     let temporario = String::from("valor");
  |         ---------- binding `temporario` declared here
4 |     referencia = &temporario;
  |                  ^^^^^^^^^^^ borrowed value does not live long enough
5 | }
  | - `temporario` dropped here while still borrowed
6 |
7 | println!("{}", referencia);
  |                ---------- borrow later used here

O Que Significa

Cada valor em Rust tem um escopo — o bloco de código onde ele existe. Quando o valor sai de escopo (o bloco {} fecha), ele é automaticamente destruído e sua memória é liberada.

Se uma referência aponta para esse valor e é usada depois que o valor foi destruído, teríamos um ponteiro pendente (dangling pointer). Em linguagens como C, isso causaria comportamento indefinido — leitura de lixo na memória, crashes aleatórios, ou vulnerabilidades de segurança.

O Rust detecta e previne isso em tempo de compilação. A mensagem “does not live long enough” significa literalmente: “este valor morre antes que a referência que aponta para ele pare de ser usada”.

Código com Erro

fn main() {
    let referencia;

    {
        let valor = String::from("Olá");
        referencia = &valor;
    } // `valor` é destruído aqui

    // ERRO: `referencia` aponta para memória liberada
    println!("{}", referencia);
}

Outro cenário comum — retornar referência para variável local:

fn criar_mensagem() -> &str {
    let msg = String::from("Olá, mundo!");
    &msg  // ERRO: `msg` será destruída quando a função retornar
}

Com vetores e closures:

fn main() {
    let mut referencias: Vec<&String> = Vec::new();

    {
        let texto = String::from("temporário");
        referencias.push(&texto);
    } // `texto` destruído, mas referência ainda no vetor

    println!("{:?}", referencias); // ERRO
}

Como Resolver

Solução 1: Estender o Tempo de Vida do Valor

Mova a declaração do valor para um escopo mais amplo:

fn main() {
    let valor = String::from("Olá"); // Declarado no escopo externo
    let referencia;

    {
        referencia = &valor;
    }

    // Funciona! `valor` ainda existe
    println!("{}", referencia);
}

Solução 2: Retornar Tipo Owned em Vez de Referência

Em vez de retornar uma referência para dados locais, retorne o valor com ownership:

fn criar_mensagem() -> String {
    let msg = String::from("Olá, mundo!");
    msg  // Transfere ownership para o chamador
}

fn main() {
    let msg = criar_mensagem();
    println!("{}", msg);
}

Solução 3: Usar 'static para Dados Estáticos

Se o valor é conhecido em tempo de compilação (como string literals), use referências estáticas:

fn saudacao() -> &'static str {
    "Olá, mundo!"  // String literals têm lifetime 'static
}

fn main() {
    println!("{}", saudacao());
}

Solução 4: Armazenar Valores Owned em Coleções

Em vez de colecionar referências, colecione os valores:

fn main() {
    let mut textos: Vec<String> = Vec::new();

    {
        let texto = String::from("permanente");
        textos.push(texto); // Move o valor para o Vec
    }

    // O Vec é o dono agora — funciona!
    println!("{:?}", textos);
}

Solução 5: Usar Rc ou Arc para Ownership Compartilhado

Quando múltiplos donos precisam do mesmo dado:

use std::rc::Rc;

fn main() {
    let dados = Rc::new(String::from("compartilhado"));

    let ref1 = Rc::clone(&dados);
    let ref2 = Rc::clone(&dados);

    println!("Ref1: {}", ref1);
    println!("Ref2: {}", ref2);
    // O valor só é destruído quando o último Rc sai de escopo
}

Padrão Comum: Structs com Referências

Se sua struct contém referências, o valor referenciado deve viver mais que a struct:

struct Parser<'a> {
    input: &'a str,
}

fn main() {
    let texto = String::from("dados para parsear");

    // `texto` vive mais que `parser` — correto
    let parser = Parser { input: &texto };
    println!("Parseando: {}", parser.input);
}

Se isso se tornar muito complexo, considere usar String em vez de &str na struct.

Veja Também