E0507: Não Pode Mover de Referência
O erro E0507 ocorre quando você tenta mover um valor para fora de uma referência emprestada. Referências no Rust são empréstimos temporários — você pode olhar e até modificar (com &mut), mas não pode levar o valor embora.
A Mensagem de Erro
error[E0507]: cannot move out of `*item` which is behind a shared reference
--> src/main.rs:4:17
|
4 | let valor = *item;
| ^^^^^
| |
| move occurs because `*item` has type `String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*item`
Outra variação comum:
error[E0507]: cannot move out of index of `Vec<String>`
--> src/main.rs:3:15
|
3 | let nome = nomes[0];
| ^^^^^^^^
| |
| move occurs because value has type `String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&nomes[0]`
O Que Significa
Uma referência (&T ou &mut T) dá acesso temporário a um valor sem transferir o ownership. Tentar mover o valor de dentro da referência violaria a regra fundamental: o dono original ainda espera que o valor esteja lá.
Se fosse permitido “extrair” um valor de uma referência, o dono original ficaria com um buraco — memória não inicializada — o que é comportamento indefinido.
Este erro aparece frequentemente em três cenários:
- Acessar elementos de uma coleção por índice (
vec[0]) - Desreferenciar uma referência (
*ref_valor) - Fazer pattern matching que move valores de dentro de structs emprestadas
Código com Erro
fn main() {
let nomes = vec![
String::from("Alice"),
String::from("Bob"),
String::from("Carol"),
];
// ERRO: tenta mover String de dentro do Vec
let primeiro = nomes[0];
println!("{}", primeiro);
}
Com structs:
struct Usuario {
nome: String,
email: String,
}
fn obter_nome(usuario: &Usuario) -> String {
// ERRO: não pode mover `nome` de uma referência
usuario.nome
}
Como Resolver
Solução 1: Usar .clone() para Copiar
A solução mais direta — crie uma cópia do valor:
fn main() {
let nomes = vec![
String::from("Alice"),
String::from("Bob"),
];
let primeiro = nomes[0].clone();
println!("{}", primeiro);
println!("Original: {:?}", nomes); // nomes continua intacto
}
fn obter_nome(usuario: &Usuario) -> String {
usuario.nome.clone()
}
Solução 2: Retornar uma Referência
Se você não precisa do ownership, retorne uma referência:
struct Usuario {
nome: String,
email: String,
}
fn obter_nome(usuario: &Usuario) -> &str {
&usuario.nome
}
fn main() {
let user = Usuario {
nome: String::from("Alice"),
email: String::from("alice@email.com"),
};
let nome = obter_nome(&user);
println!("Nome: {}", nome);
}
Solução 3: Usar .take() com Option
Quando o valor está dentro de um Option e você tem acesso mutável, use .take():
fn main() {
let mut valor: Option<String> = Some(String::from("dados"));
// .take() retira o valor e deixa None no lugar
let extraido = valor.take();
println!("Extraído: {:?}", extraido); // Some("dados")
println!("Original: {:?}", valor); // None
}
Solução 4: Usar std::mem::swap ou std::mem::replace
Quando precisa extrair um valor de uma referência mutável, substitua-o por outro valor:
use std::mem;
struct Fila {
itens: Vec<String>,
}
impl Fila {
fn drenar(&mut self) -> Vec<String> {
// Troca `self.itens` por um Vec vazio, retornando o original
mem::take(&mut self.itens)
}
}
fn main() {
let mut fila = Fila {
itens: vec![String::from("a"), String::from("b")],
};
let itens = fila.drenar();
println!("Drenados: {:?}", itens);
println!("Fila agora: {:?}", fila.itens); // []
}
Solução 5: Usar remove() ou swap_remove() em Vecs
Se você quer extrair um elemento específico de um Vec:
fn main() {
let mut nomes = vec![
String::from("Alice"),
String::from("Bob"),
String::from("Carol"),
];
// Remove e retorna o elemento no índice 0
let primeiro = nomes.remove(0);
println!("Removido: {}", primeiro);
println!("Restantes: {:?}", nomes);
// swap_remove é mais rápido (O(1)) mas não preserva ordem
let ultimo = nomes.swap_remove(0);
println!("Removido: {}", ultimo);
}
Quando Usar Cada Solução
| Situação | Solução Recomendada |
|---|---|
| Precisa apenas ler o valor | Retorne referência (&T) |
| Precisa de uma cópia independente | Use .clone() |
Valor em Option<T> com &mut | Use .take() |
| Precisa substituir por valor padrão | Use mem::take() ou mem::replace() |
| Quer remover de uma coleção | Use .remove() ou .swap_remove() |