Introdução: Por que Rust Parece Difícil?
Rust é uma linguagem de programação de sistemas moderna que garante segurança de memória sem um coletor de lixo. No entanto, seu sistema de tipos estrito e modelo único de ownership (propriedade) frequentemente confundem iniciantes. Se você está começando a aprender Rust e vê constantemente mensagens vermelhas do compilador, não se desespere — isso é normal. Neste artigo, vamos detalhar os 10 erros mais comuns de desenvolvedores Rust iniciantes e mostrar como corrigi-los.
1. Ignorando o borrow checker
O erro mais popular é tentar usar um valor após uma movimentação (move) ou criar uma referência mutável. O compilador Rust (borrow checker) aplica rigorosamente as regras de ownership.
Problema
let s1 = String::from("hello");let s2 = s1; // s1 movido para s2println!("{}", s1); // Erro! s1 não possui mais os dadosSolução
Use clone() se precisar copiar dados, ou passe referências &:
let s1 = String::from("hello");let s2 = &s1; // emprestandoprintln!("{} and {}", s1, s2); // Funciona!Dica: Se o compilador reclamar sobre ownership — você provavelmente precisa de uma referência, não de uma movimentação completa.
2. Confusão entre String e &str
Iniciantes frequentemente não entendem a diferença entre o tipo proprietário String e a fatia (slice) &str. Isso leva a erros de tipo e alocações desnecessárias.
Problema
fn greet(name: &str) { println!("Hello, {}!", name);}
let my_name = String::from("Anna");greet(my_name); // Erro: esperava &str, encontrou StringSolução
Passe uma referência a String — ela será automaticamente convertida para &str:
greet(&my_name); // Funciona graças à coerção DerefUse String para possuir e modificar strings, e &str para leitura e passagem para funções.
3. Uso excessivo de unwrap() e expect()
Os métodos unwrap() e expect() são uma maneira rápida de lidar com Option ou Result, mas causam pânico (panic) em caso de erro. Isso é inaceitável em código de produção.
Problema
let number: Option<i32> = None;let value = number.unwrap(); // Pânico!Solução
Use match ou os métodos unwrap_or, unwrap_or_else:
let value = number.unwrap_or(0); // Retorna 0 se for None// Ou com matchmatch number { Some(v) => println!("{}", v), None => println!("Valor ausente"),}Para Result, use o operador ? para propagar o erro para cima.
4. Uso incorreto de referências mutáveis
A regra "uma referência mutável OU várias referências imutáveis" é constantemente violada.
Problema
let mut data = vec![1, 2, 3];let ref1 = &mut data;let ref2 = &mut data; // Erro!println!("{}", ref1);Solução
Limite o escopo das referências mutáveis usando chaves:
let mut data = vec![1, 2, 3];{ let ref1 = &mut data; ref1.push(4);} // ref1 sai de escopolet ref2 = &mut data; // Agora é possíveref2.push(5);5. Lifetimes esquecidos
Quando o compilador exige especificar explicitamente um lifetime, os iniciantes ficam presos. O erro mais comum é retornar uma referência a uma variável local.
Problema
fn get_ref() -> &str { let s = String::from("test"); &s // Erro: retornando uma referência a uma variável local}Solução
Ou retorne o tipo proprietário String, ou aceite uma referência como argumento: