E0382: Uso de Valor Após Move
O erro E0382 é provavelmente o erro mais comum que todo desenvolvedor Rust encontra, especialmente no início da jornada com a linguagem. Ele está diretamente ligado ao conceito fundamental de ownership (posse) do Rust.
A Mensagem de Erro
Quando o compilador detecta esse problema, você verá algo como:
error[E0382]: borrow of moved value: `nome`
--> src/main.rs:4:20
|
2 | let nome = String::from("Rust Brasil");
| ---- move occurs because `nome` has type `String`, which does not implement the `Copy` trait
3 | let outro = nome;
| ---- value moved here
4 | println!("{}", nome);
| ^^^^ value borrowed here after move
O Que Significa
No Rust, cada valor tem exatamente um dono (owner). Quando você atribui um valor a outra variável, o ownership é transferido (move). A variável original deixa de ser válida e não pode mais ser usada.
Isso acontece com tipos que estão alocados no heap e não implementam o trait Copy, como String, Vec<T>, Box<T>, HashMap e outros. Tipos simples como i32, f64, bool e char implementam Copy e são copiados automaticamente, sem causar move.
O sistema de ownership existe para garantir segurança de memória sem precisar de garbage collector. Quando o dono sai de escopo, a memória é liberada automaticamente. Se houvesse dois donos, teríamos um double free — e o Rust impede isso em tempo de compilação.
Código com Erro
fn main() {
let mensagem = String::from("Olá, Rust!");
// Aqui o ownership de `mensagem` é transferido para `copia`
let copia = mensagem;
// ERRO: `mensagem` não é mais válida após o move
println!("{}", mensagem);
}
Outro cenário comum é ao passar um valor para uma função:
fn exibir(texto: String) {
println!("{}", texto);
}
fn main() {
let nome = String::from("Brasil");
exibir(nome);
// ERRO: `nome` foi movido para a função `exibir`
println!("Nome: {}", nome);
}
Como Resolver
Solução 1: Usar .clone() para Copiar o Valor
Se você precisa usar o valor em dois lugares, pode criar uma cópia explícita:
fn main() {
let mensagem = String::from("Olá, Rust!");
let copia = mensagem.clone();
// Ambas são válidas agora
println!("Original: {}", mensagem);
println!("Cópia: {}", copia);
}
Nota: .clone() cria uma cópia completa dos dados no heap, o que tem custo de performance. Use quando realmente precisar de duas cópias independentes do valor.
Solução 2: Usar Referências (Borrowing)
Na maioria dos casos, você não precisa de uma cópia — apenas precisa ler o valor. Use uma referência com &:
fn exibir(texto: &String) {
println!("{}", texto);
}
fn main() {
let nome = String::from("Brasil");
exibir(&nome); // Emprestamos uma referência
// `nome` continua válido!
println!("Nome: {}", nome);
}
Melhor ainda, use &str em vez de &String para maior flexibilidade:
fn exibir(texto: &str) {
println!("{}", texto);
}
fn main() {
let nome = String::from("Brasil");
exibir(&nome);
println!("Nome: {}", nome);
}
Solução 3: Reestruturar o Código
Às vezes a melhor solução é repensar a lógica para evitar usar o valor após movê-lo:
fn main() {
let nome = String::from("Brasil");
// Use o valor ANTES de movê-lo
println!("Nome: {}", nome);
// Agora pode mover sem problemas
let outro = nome;
println!("Outro: {}", outro);
}
Ou retorne o valor da função para recuperar o ownership:
fn processar(texto: String) -> String {
println!("Processando: {}", texto);
texto // Retorna o ownership
}
fn main() {
let nome = String::from("Brasil");
let nome = processar(nome); // Recupera o ownership
println!("Nome: {}", nome);
}
Dica Rápida
Se você está vindo de linguagens com garbage collector (Java, Python, JavaScript), lembre-se: no Rust, a atribuição let b = a com tipos do heap move o valor, não copia. Para copiar, use .clone() explicitamente ou passe por referência com &.