Code Review em Rust: o que verificar para o código não desmoronar

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que code review em Rust não é apenas verificar chaves



Rust é uma linguagem que promete segurança de memória e alta performance. Mas mesmo o compilador mais rigoroso não protege contra erros lógicos, código não idiomático ou uso injustificado de unsafe. Code review em Rust é uma arte. Você não está apenas verificando se as chaves estão fechadas. Você verifica como o desenvolvedor contornou (ou não) as limitações do borrow checker, quão eficientemente usa iteradores e se não está tentando "burlar" o sistema com ponteiros brutos.



Neste artigo, falarei sobre quais aspectos prestar atenção ao revisar código em Rust. Sem teoria desnecessária — apenas dicas práticas, exemplos e uma checklist que você pode pendurar na parede (ou salvar nos favoritos). Vamos lá!



1. Ownership, borrowing e lifetimes: a principal fonte de dor



A primeira coisa a verificar é se o sistema de ownership está funcionando corretamente. Mesmo que o código compile, isso não significa que ele está correto. Problemas típicos:



  • Clonagem excessiva. Quando poderia ser usada uma referência, o desenvolvedor copia os dados. Isso prejudica a performance.
  • Borrowing mutável e imutável. Se no mesmo escopo houver &mut T e &T simultaneamente — haverá erro. Mas às vezes é possível reordenar o código para evitar isso.
  • Lifetimes incorretos. Especialmente em estruturas complexas com múltiplas referências.


Exemplo: código ruim

fn process(data: &Vec<i32>) -> i32 {    let mut sum = 0;    for &x in data.iter() {        sum += x;    }    // Tudo ok, mas por que passar &Vec, se pode &[i32]?    sum}


Código bom

fn process(data: &[i32]) -> i32 {    data.iter().sum()}


O que verificar na revisão: não está sendo passado &Vec, &String ou &HashMap onde um slice é suficiente? clone() está sendo usado desnecessariamente? As anotações de lifetime estão corretas?



2. Unsafe: zona vermelha



Blocos unsafe são como um alçapão aberto no Rust seguro. Eles devem ser justificados, mínimos e cuidadosamente documentados. No code review, preste atenção em:



  • Por que unsafe está sendo usado? Muitas vezes é possível usar abstrações seguras.
  • Corretude dos ponteiros brutos. Um ponteiro nulo está sendo desreferenciado? Uma referência está pendente após a liberação de memória?
  • Invariantes. Código com unsafe deve descrever explicitamente quais invariantes ele mantém.


Exemplo: unsafe perigoso

unsafe fn dangerous() {    let ptr = 0x12345 as *mut i32;    *ptr = 42; // E se não houver nada neste endereço?}


Esse código não deve passar na revisão. Mesmo que "funcione" — isso não é um argumento.



Unsafe bom

unsafe fn init_buffer(buf: &mut [u8]) {    // Temos certeza de que buf aponta para memória válida,    // pois a parte chamadora garante isso.    std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len());}


O que verificar: há um comentário justificando cada unsafe? Existem testes que verificam casos limite? As garantias de segurança estão sendo violadas?



3. Closures e estilo funcional



Rust incentiva a abordagem funcional: iteradores, closures, map, filter, fold. Mas isso pode levar à complexidade excessiva. Na revisão, observe:



  • Há abuso de closures? Se uma closure captura muitas variáveis, talvez valha a pena extrair a lógica para uma função separada.

Blogs

Book Recommendations