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.