Principais erros de iniciantes em Rust: de A a Z
\n\nRust é uma linguagem de programação poderosa e segura, mas seu sistema rigoroso de ownership e borrowing frequentemente confunde os iniciantes. Neste artigo, vamos analisar os erros mais comuns que os desenvolvedores iniciantes em Rust enfrentam. Cada erro é acompanhado por um exemplo de código, explicação e a solução correta. Vamos lá!
\n\n1. Ignorar o sistema de ownership
\n\nO erro mais comum é tentar usar um valor após ele ter sido movido. Em Rust, cada valor pode ter apenas um dono.
\n\n❌ Código errado:
\nfn main() {\n let s1 = String::from("olá");\n let s2 = s1;\n println!("{}", s1); // Erro! s1 não é mais dono da string\n}\n\n\n✅ Solução correta:
\nfn main() {\n let s1 = String::from("olá");\n let s2 = s1.clone(); // Cópia explícita\n println!("{}", s1); // Agora funciona\n println!("{}", s2);\n}\n\n\nDica: Use .clone() apenas quando realmente necessário. Para tipos primitivos (i32, bool), a cópia ocorre automaticamente.
2. Confusão entre String e &str
\n\nIniciantes frequentemente não entendem a diferença entre a string com ownership String e a fatia de string &str. Isso leva a erros ao passar strings para funções.
❌ Código errado:
\nfn print_message(msg: String) {\n println!("{}", msg);\n}\n\nfn main() {\n let greeting = "Olá"; // &str\n print_message(greeting); // Erro! Espera-se String\n}\n\n\n✅ Solução correta:
\nfn print_message(msg: &str) {\n println!("{}", msg);\n}\n\nfn main() {\n let greeting = "Olá";\n print_message(greeting); // Funciona!\n \n let owned = String::from("Mundo");\n print_message(&owned); // &String é convertido automaticamente para &str\n}\n\n\nRegra de ouro: Em parâmetros de funções, use &str se você não precisar transferir a ownership da string.
3. Violação das regras de borrowing
\n\nRust não permite ter simultaneamente uma referência mutável e uma imutável para o mesmo objeto. Isso protege contra condições de corrida.
\n\n❌ Código errado:
\nfn main() {\n let mut data = vec![1, 2, 3];\n let ref1 = &data;\n let ref2 = &mut data; // Erro! Já existe uma referência imutável\n println!("{}", ref1);\n}\n\n\n✅ Solução correta:
\nfn main() {\n let mut data = vec![1, 2, 3];\n {\n let ref1 = &data;\n println!("{}", ref1); // ref1 vive apenas neste bloco\n } // ref1 sai de escopo\n let ref2 = &mut data; // Agora é possível\n ref2.push(4);\n println!("{:?}", ref2);\n}\n\n\nImportante: O escopo de uma referência termina no seu último uso. O compilador Rust é inteligente o suficiente para rastrear isso.
\n\n4. Problemas com lifetimes
\n\nErros relacionados a anotações de lifetime assustam os iniciantes mais do que qualquer outra coisa. O mais típico é retornar uma referência a uma variável local.
\n\n❌ Código errado:
\nfn get_reference() -> &str {\n let local = String::from("teste");\n &local // Erro! local será destruída após sair da função\n}\n\n\n✅ Solução correta (via ownership):
\nfn get_reference() -> String {\n let local = String::from("teste");\n local // Retorna a ownership\n}\n\nfn main() {\n let s = get_reference();\n println!("{}", s);\n}\n\n\n✅ Solução correta (via parâmetro):
\nfn get_reference<'a>(input: &'a str) -> &'a str {\n input // Retorna a referência com o mesmo lifetime\n}\n\nfn main() {\n let data = String::from("teste");\n let result = get_reference(&data);\n println!("{}", re