«Use of moved value» em Rust: como corrigir e não enlouquecer

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

«Use of moved value» em Rust: por que isso acontece e como lidar com isso

\n\n

Se você acabou de começar a estudar Rust, provavelmente já se deparou com a mensagem enigmática: error[E0382]: use of moved value. O compilador reclama, você coça a cabeça, e o código, que é logicamente absolutamente correto, se recusa a compilar. Familiar? Bem-vindo ao mundo da propriedade e do empréstimo — conceitos-chave do Rust que o tornam seguro, mas às vezes deixam até desenvolvedores experientes perplexos.

\n\n

Este artigo não é uma documentação seca, mas uma análise viva do problema. Vamos examinar por que ocorre o erro use of moved value, com exemplos reais de código e, principalmente, o que fazer com ele. Você aprenderá a pensar como o borrow checker e parará de lutar contra ele. Vamos lá!

\n\n

O que é «move» no Rust e por que o compilador é tão rigoroso?

\n\n

No Rust, cada valor tem exatamente um proprietário (owner). Quando você atribui um valor a outra variável ou o passa para uma função, a propriedade é movida (move). Após a movimentação, a variável original se torna inválida — o compilador proíbe o acesso a ela. Essa é a raiz do erro use of moved value.

\n\n

Veja o exemplo mais simples:

\n\n
let s1 = String::from("olá");\nlet s2 = s1; // A propriedade é movida de s1 para s2\nprintln!("{}", s1); // ERRO: use of moved value: `s1`
\n\n

Por que isso? String não é uma simples cópia na pilha. Ela armazena dados no heap. Se o Rust simplesmente copiasse o ponteiro, ao liberar a memória, ambas as variáveis tentariam deletá-la — double free. Em vez disso, o Rust «move» a propriedade: agora s2 é responsável pela memória, e s1 não existe mais do ponto de vista do compilador. Essa é a ideia principal da semântica de movimentação no Rust.

\n\n

Cenários típicos que levam ao erro

\n\n

O erro use of moved value ocorre mais frequentemente em três situações:

\n\n
    \n
  • Passar um valor para uma função
  • \n
  • Atribuir um valor a outra variável
  • \n
  • Usar um valor em um loop ou iterador
  • \n
\n\n

Vamos examinar cada caso em detalhes.

\n\n

1. Passagem para uma função sem retorno

\n\n
fn print_string(s: String) {\n    println!("{}", s);\n}\n\nfn main() {\n    let my_string = String::from("Rust");\n    print_string(my_string); // propriedade movida\n    println!("{}", my_string); // erro! use of moved value\n}
\n\n

Após a chamada de print_string, a propriedade de my_string foi para a função. Quando a função termina, s é deletada, e my_string não é mais válida. O compilador protege você de usar um objeto morto.

\n\n

2. Atribuição sem cópia

\n\n

Já vimos este exemplo com String. Mas é importante: nem todos os tipos se comportam assim. Tipos simples como i32, bool, f64 implementam a trait Copy. Eles não são movidos, mas copiados automaticamente.

\n\n
let x = 5;\nlet y = x; // cópia, não movimentação\nprintln!("{}", x); // funciona!
\n\n

Tipos que armazenam dados no heap (String, Vec, Box) não implementam Copy — apenas Clone. Portanto, eles são movidos.

\n\n

3. Iteração sobre uma coleção

\n\n

Outra fonte comum de erros são os loops for:

\n\n
let v = vec![1, 2, 3];\nfor x in v { // v é movido para o iterador\n    println!("{}", x);\n}\nprintln!("{:?}", v); // erro! use of moved value
\n\n

Quando você escreve for x in v, na verdade está chamando into_iter(), que consome o vetor. Após o loop, v não existe mais.

\n\n

Como corrigir: 4 maneiras comprovadas

\n\n

Agora

Blogs

Book Recommendations