E0507: Não Pode Mover de Referência no Rust

Como resolver o erro E0507 do Rust: cannot move out of borrowed content. Aprenda a usar clone, take, swap e outras técnicas para resolver este erro comum.

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:

  1. Acessar elementos de uma coleção por índice (vec[0])
  2. Desreferenciar uma referência (*ref_valor)
  3. 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çãoSolução Recomendada
Precisa apenas ler o valorRetorne referência (&T)
Precisa de uma cópia independenteUse .clone()
Valor em Option<T> com &mutUse .take()
Precisa substituir por valor padrãoUse mem::take() ou mem::replace()
Quer remover de uma coleçãoUse .remove() ou .swap_remove()

Veja Também