Iteração por intervalo com passo não padrão em Rust: 3 maneiras

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

Como percorrer números com passo 3, 5 ou 100 em Rust? Análise completa



Imagine: você está programando em Rust e precisa exibir todos os números pares de 0 a 20. Ou, digamos, construir a sequência 0, 5, 10, 15, 20. Em Python, você simplesmente escreveria range(0, 21, 5) — e pronto. E como fazer em Rust? Aqui há nuances, e hoje vamos analisá-las.



Esta pergunta é uma das mais populares no Stack Overflow (milhares de visualizações). E não é surpresa: o padrão for i in 0..10 funciona apenas com passo 1. E se precisar de um passo diferente? Acontece que existem três maneiras, cada uma com seus prós e armadilhas.



Não vamos apenas mostrar o código — vamos comparar as abordagens em termos de desempenho, legibilidade e flexibilidade. Vamos lá!



Por que o Rust não tem um range embutido com passo?



Resposta curta: porque Range em Rust é um iterador simples que gera uma sequência de números inteiros. Ele não suporta passo por padrão para permanecer o mais leve e previsível possível. Mas os desenvolvedores forneceram métodos que resolvem esse problema.



Resposta longa: no ecossistema Rust, a filosofia é "explícito é melhor que implícito". Em vez de incorporar o passo na sintaxe do intervalo, os criadores propuseram ferramentas flexíveis de adaptação de iteradores. E isso abre mais possibilidades do que parece.



Método 1: step_by() — o caminho mais direto



Na biblioteca padrão do Rust, existe o método step_by(n), que cria um iterador pulando a cada n-1 elementos. Veja como funciona:



fn main() {    // Exibe números de 0 a 20 com passo 5    for i in (0..=20).step_by(5) {        println!("{}", i);    }    // Saída: 0, 5, 10, 15, 20}


Observe: usei 0..=20 (inclusivo), não 0..20 (exclusivo). Se precisar de passo 3 até 10, escreva (0..10).step_by(3) — obterá 0, 3, 6, 9.



Vantagens do step_by():

  • Simplicidade — uma linha, sem closures
  • Legibilidade — fica claro o que está sendo feito
  • Desempenho — sobrecarga mínima


Desvantagens:

  • Funciona apenas com números inteiros (i32, u64, etc.)
  • Não é possível definir um passo dinâmico a cada iteração
  • Surgiu apenas no Rust 1.28 (mas já faz tempo)


Este método é a escolha ideal para 90% das tarefas. Se você precisa apenas percorrer números com passo constante — use step_by().



Método 2: filter() — quando o passo é uma condição



E se o passo não for constante? Por exemplo, precisa exibir números que são divisíveis por 3 sem resto. Ou números onde a soma dos dígitos é maior que 5. É aí que o filter() entra em ação:



fn main() {    // Todos os números de 0 a 30, múltiplos de 4    for i in (0..=30).filter(|x| x % 4 == 0) {        println!("{}", i);    }    // Saída: 0, 4, 8, 12, 16, 20, 24, 28

// Agora — números que não são divisíveis por 3 for i in (0..20).filter(|x| x % 3 != 0) { println!("{}", i); } // Saída: 1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19}


Aqui passamos uma closure que verifica cada número. filter() mantém apenas os elementos para os quais a condição é verdadeira.



Quando filter() é melhor que step_by():

  • O passo depende do valor (ex.: "todos os números primos")
  • Precisa combinar com outras condições
  • O passo não é constante (ex.: números de Fibonacci)


Desvantagens:

  • Um pouco mais lento que step_by() — é necessário verificar cada número
  • O código pode ser menos óbvio para iniciantes


Pessoalmente, uso filter() quando preciso não apenas de "cada n-ésimo", mas de "cada um que atende a uma regra". É mais poderoso, mas requer mais atenção.

Blogs

Book Recommendations