E0505: Mover Valor Enquanto Emprestado no Rust

Como resolver o erro E0505 do Rust: não é possível mover um valor enquanto ele está emprestado. Entenda o conflito entre move e borrow com exemplos práticos.

E0505: Mover Valor Enquanto Emprestado

O erro E0505 surge quando você tenta mover (transferir o ownership de) um valor que ainda tem referências ativas apontando para ele. É a interseção de dois conceitos fundamentais do Rust: ownership e borrowing.

A Mensagem de Erro

error[E0505]: cannot move out of `dados` because it is borrowed
 --> src/main.rs:5:15
  |
3 |     let ref_dados = &dados;
  |                     ------ borrow of `dados` occurs here
4 |
5 |     let novo = dados;
  |               ^^^^^ move out of `dados` occurs here
6 |
7 |     println!("{:?}", ref_dados);
  |                      --------- borrow later used here

O Que Significa

Quando você cria uma referência (&dados), o Rust garante que essa referência permaneça válida enquanto estiver em uso. Se o valor fosse movido para outra variável enquanto a referência existe, a referência apontaria para memória inválida — um dangling reference.

O Rust previne esta situação em tempo de compilação: se existe qualquer referência ativa (empréstimo) para um valor, esse valor não pode ser movido.

Pense assim: se você emprestou seu carro para alguém, não pode vendê-lo enquanto a pessoa está usando. Primeiro ela tem que devolver (o empréstimo precisa terminar), depois você pode vender (mover o ownership).

Código com Erro

fn main() {
    let dados = String::from("informação importante");

    // Cria uma referência para `dados`
    let referencia = &dados;

    // ERRO: tenta mover `dados` para `consumir`
    consumir(dados);

    // A referência ainda seria usada aqui
    println!("Ref: {}", referencia);
}

fn consumir(s: String) {
    println!("Consumido: {}", s);
}

Outro cenário frequente com structs:

struct Servidor {
    nome: String,
    conexoes: Vec<String>,
}

fn main() {
    let servidor = Servidor {
        nome: String::from("api-01"),
        conexoes: vec![],
    };

    let nome_ref = &servidor.nome;

    // ERRO: mover `servidor` invalida `nome_ref`
    let outro = servidor;

    println!("Nome: {}", nome_ref);
}

Como Resolver

Solução 1: Terminar o Empréstimo Antes do Move

Reorganize o código para que a referência não seja mais usada antes de mover o valor:

fn main() {
    let dados = String::from("informação importante");

    // Usa a referência ANTES de mover
    let referencia = &dados;
    println!("Ref: {}", referencia);
    // Empréstimo encerrado (último uso)

    // Agora pode mover
    consumir(dados);
}

fn consumir(s: String) {
    println!("Consumido: {}", s);
}

Solução 2: Usar Referências em Vez de Move

Se a função não precisa do ownership, passe uma referência:

fn exibir(s: &str) {
    println!("Exibindo: {}", s);
}

fn main() {
    let dados = String::from("informação importante");
    let referencia = &dados;

    // Passa referência — sem move
    exibir(&dados);

    println!("Ref: {}", referencia);
}

Solução 3: Clonar o Valor

Se você precisa tanto do empréstimo quanto do move, clone o valor:

fn consumir(s: String) {
    println!("Consumido: {}", s);
}

fn main() {
    let dados = String::from("informação importante");
    let referencia = &dados;

    // Clona para mover a cópia, mantendo o original
    consumir(dados.clone());

    println!("Ref: {}", referencia);
}

Solução 4: Usar Blocos para Controlar Escopos

fn consumir(s: String) {
    println!("Consumido: {}", s);
}

fn main() {
    let dados = String::from("informação importante");

    {
        let referencia = &dados;
        println!("Ref: {}", referencia);
    } // referencia sai de escopo aqui

    consumir(dados); // move liberado
}

Diferença Entre E0505 e E0382

  • E0382 (Uso após move): Você moveu o valor e tenta usá-lo depois.
  • E0505 (Mover enquanto emprestado): Você tenta mover um valor que ainda tem referências ativas.

Ambos protegem contra acesso a memória inválida, mas por ângulos diferentes. O E0505 foca na existência de referências pendentes, enquanto o E0382 foca na tentativa de usar um valor que já não está mais disponível.

Veja Também