E0499: Dois Empréstimos Mutáveis
O erro E0499 ocorre quando você tenta criar duas referências mutáveis para o mesmo dado simultaneamente. O Rust proíbe isso terminantemente: apenas uma referência mutável pode existir por vez.
A Mensagem de Erro
error[E0499]: cannot borrow `dados` as mutable more than once at a time
--> src/main.rs:5:16
|
3 | let ref1 = &mut dados;
| --------- first mutable borrow occurs here
4 |
5 | let ref2 = &mut dados;
| ^^^^^^^^^ second mutable borrow occurs here
6 |
7 | ref1.push(1);
| ---- first borrow later used here
O Que Significa
A regra de exclusividade de referências mutáveis é uma das garantias mais importantes do Rust. Ela previne data races em tempo de compilação.
Um data race acontece quando:
- Dois ou mais ponteiros acessam o mesmo dado ao mesmo tempo
- Pelo menos um deles está escrevendo
- Não há mecanismo de sincronização
Se o Rust permitisse duas referências mutáveis, seria possível que uma modificação “quebrasse” as invariantes que a outra referência espera. Por exemplo, um Vec poderia ser realocado por uma referência enquanto a outra aponta para a memória antiga.
A regra é: você pode ter muitos leitores (&T) ou um único escritor (&mut T), mas nunca ambos.
Código com Erro
fn main() {
let mut dados = vec![1, 2, 3];
let ref1 = &mut dados;
let ref2 = &mut dados; // ERRO: segunda referência mutável
ref1.push(4);
ref2.push(5);
}
Cenário comum — dividir um dado entre duas funções que modificam:
fn adicionar(lista: &mut Vec<i32>, valor: i32) {
lista.push(valor);
}
fn main() {
let mut numeros = vec![1, 2, 3];
let ref_mut = &mut numeros;
// ERRO: `numeros` já está emprestado como mutável
adicionar(&mut numeros, 4);
ref_mut.push(5);
}
Outro padrão problemático com structs:
struct Estado {
contador: i32,
historico: Vec<i32>,
}
impl Estado {
fn incrementar(&mut self) {
self.contador += 1;
// Isso funciona porque o compilador sabe que são campos diferentes
self.historico.push(self.contador);
}
}
Como Resolver
Solução 1: Usar Referências Sequencialmente
Graças ao NLL (Non-Lexical Lifetimes), basta não usar as referências ao mesmo tempo:
fn main() {
let mut dados = vec![1, 2, 3];
let ref1 = &mut dados;
ref1.push(4);
// ref1 não é mais usado — empréstimo encerrado
let ref2 = &mut dados;
ref2.push(5);
// Funciona perfeitamente
}
Solução 2: Usar Escopos Explícitos
fn main() {
let mut dados = vec![1, 2, 3];
{
let ref1 = &mut dados;
ref1.push(4);
} // ref1 sai de escopo
{
let ref2 = &mut dados;
ref2.push(5);
} // ref2 sai de escopo
println!("{:?}", dados);
}
Solução 3: Split Borrowing (Empréstimos de Campos Separados)
O Rust permite emprestar campos diferentes de uma struct como mutáveis simultaneamente:
struct Jogador {
vida: i32,
pontos: i32,
}
fn main() {
let mut jogador = Jogador { vida: 100, pontos: 0 };
let vida = &mut jogador.vida;
let pontos = &mut jogador.pontos;
// Funciona! São campos diferentes
*vida -= 10;
*pontos += 50;
println!("Vida: {}, Pontos: {}", vida, pontos);
}
Para slices, use split_at_mut:
fn main() {
let mut dados = vec![1, 2, 3, 4, 5];
// Divide o slice em duas partes mutáveis
let (esquerda, direita) = dados.split_at_mut(3);
esquerda[0] = 10;
direita[0] = 40;
println!("{:?}", dados); // [10, 2, 3, 40, 5]
}
Solução 4: Usar Cell ou RefCell para Mutabilidade Interior
Quando o design exige múltiplos acessos mutáveis, use o padrão de mutabilidade interior:
use std::cell::RefCell;
fn main() {
let dados = RefCell::new(vec![1, 2, 3]);
// Múltiplos empréstimos mutáveis em momentos diferentes
dados.borrow_mut().push(4);
dados.borrow_mut().push(5);
println!("{:?}", dados.borrow());
}
Atenção: RefCell move a verificação de empréstimos para tempo de execução. Se você violar as regras, o programa entrará em panic em vez de gerar um erro de compilação. Use com cuidado.
Para cenários multithreaded, use Arc<Mutex<T>>:
use std::sync::{Arc, Mutex};
fn main() {
let dados = Arc::new(Mutex::new(vec![1, 2, 3]));
let dados_clone = Arc::clone(&dados);
dados.lock().unwrap().push(4);
dados_clone.lock().unwrap().push(5);
}