Introdução: O momento em que o Rust «não te entende»
\nVocê está programando em Rust. Tudo vai bem. O compilador fica em silêncio. Você se sente um mestre da memória. E então — bum! — aparece ela:
\nerror[E0507]: cannot move out of borrowed content\n --> src/main.rs:10:9\n |\n10 | let value = self.data;\n | ^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait\n\nOu sua parente próxima:
\nerror[E0507]: cannot move out of `*self` which is behind a shared reference\n\nSe você é iniciante, isso parece uma maldição mágica. Se é experiente — sabe que é apenas mais uma lição do Borrow Checker (verificador de empréstimos).
\nNeste artigo, vamos analisar o que significam esses erros, por que o Rust é tão rigoroso e — o mais importante — como corrigi-los com exemplos de código reais. Não é teoria chata, mas um guia prático para sobreviver no mundo da propriedade e do empréstimo.
\n\nResumindo o essencial: Propriedade, empréstimo e «movimentação»
\nAntes de nos aprofundarmos, vamos lembrar os três pilares do Rust:
\n- \n
- Propriedade (Ownership): Cada valor no Rust tem exatamente um dono. \n
- Empréstimo (Borrowing): Você pode «emprestar» um valor por referência (&T — imutável, &mut T — mutável), sem tomar a propriedade. \n
- Movimentação (Move): Quando você atribui um valor a uma nova variável ou o passa para uma função sem &, a propriedade é movida. A variável original se torna inválida. \n
O erro cannot move out of borrowed content ocorre exatamente quando você tenta mover um valor para o qual você tem apenas uma referência (&T). O Rust proíbe isso, porque após a movimentação a referência se tornará «pendente» (dangling pointer). E o Rust, como você sabe, não perdoa essas coisas.
Cenário 1: Tentativa de mover um campo de estrutura via &self
\nO caso mais comum. Você tem uma estrutura e quer retornar um de seus campos a partir de um método que recebe &self.
Código com erro
\nstruct User {\n name: String,\n age: u32,\n}\n\nimpl User {\n // Tentando entregar o name "definitivamente"\n fn give_name(&self) -> String {\n self.name // ERRO!\n }\n}\n\nfn main() {\n let user = User { name: "Alice".to_string(), age: 30 };\n let name = user.give_name();\n println!("{}", name);\n}\n\nO compilador dirá:
\nerror[E0507]: cannot move out of `self.name` which is behind a shared reference\n\nPor quê? self é &User. Nós não possuímos self, apenas o emprestamos. Tentar mover self.name (tipo String, que não implementa Copy) significa que, após a chamada do método, o dono (user) perderá seu campo. Mas a referência &self ainda existe! O Rust nos protege de um desastre.
Como corrigir?
\nExistem três caminhos principais, dependendo da sua tarefa.
\n\nManeira 1: Clonagem (a mais simples, mas nem sempre eficiente)
\nSe você precisa exatamente do valor, e não de uma referência, e está disposto a pagar pela cópia:
\nfn give_name(&self) -> String {\n self.name.clone() // Funciona! Cria uma cópia.\n}\n\nDesvantagem: clone() para String faz uma cópia completa dos dados no heap. Em strings grandes, isso é caro.
Maneira 2: Retorno de referência (alteramos a assinatura)
\nSe o código chamador precisar apenas de uma referência ao campo:
\nfn give_name(&self) -> &String {\n &self.name // Retornamos uma referência, sem movimentação\n}\n\nAgora não movemos, mas emprestamos. Tudo justo. O código chamador receberá