Rust

Como Usar Iteradores em Rust: map, filter, fold e Lazy Evaluation em Produção

7 min de leitura

Como Usar Iteradores em Rust: map, filter, fold e Lazy Evaluation em Produção

Entendendo Iteradores em Rust Iteradores são um conceito fundamental em Rust que representam uma sequência de elementos que podem ser processados um de cada vez. Diferente de linguagens como Python ou JavaScript, Rust oferece iteradores com segurança de memória e performance excepcional. Um iterador implementa a trait , que exige apenas um método: . Este método retorna , sendo enquanto há elementos e quando termina. A beleza dos iteradores em Rust está na combinação com os adaptadores (como e ), que permitem transformações expressivas e eficientes. Map, Filter e Fold: Os Pilares Funcionais Map: Transformando Elementos O é um adaptador que transforma cada elemento do iterador usando uma função. Ele retorna um novo iterador com os elementos transformados, sem consumir o original. Este é um operador funcional puro que não modifica o estado original dos dados. O é particularmente poderoso quando combinado com outras operações, criando pipelines de transformação elegantes e legíveis. Filter: Selecionando Elementos O retorna um iterador contendo

<h2>Entendendo Iteradores em Rust</h2>

<p>Iteradores são um conceito fundamental em Rust que representam uma sequência de elementos que podem ser processados um de cada vez. Diferente de linguagens como Python ou JavaScript, Rust oferece iteradores com segurança de memória e performance excepcional. Um iterador implementa a trait <code>Iterator</code>, que exige apenas um método: <code>next()</code>. Este método retorna <code>Option&lt;T&gt;</code>, sendo <code>Some(valor)</code> enquanto há elementos e <code>None</code> quando termina. A beleza dos iteradores em Rust está na combinação com os adaptadores (como <code>map</code> e <code>filter</code>), que permitem transformações expressivas e eficientes.</p>

<pre><code class="language-rust">fn main() {

let numeros = vec![1, 2, 3, 4, 5];

let iter = numeros.iter();

// Iteradores são lazy, não fazem nada até serem consumidos

for num in iter {

println!(&quot;{}&quot;, num);

}

}</code></pre>

<h2>Map, Filter e Fold: Os Pilares Funcionais</h2>

<h3>Map: Transformando Elementos</h3>

<p>O <code>map</code> é um adaptador que transforma cada elemento do iterador usando uma função. Ele retorna um novo iterador com os elementos transformados, sem consumir o original. Este é um operador funcional puro que não modifica o estado original dos dados. O <code>map</code> é particularmente poderoso quando combinado com outras operações, criando pipelines de transformação elegantes e legíveis.</p>

<pre><code class="language-rust">fn main() {

let numeros = vec![1, 2, 3, 4, 5];

// Map transforma cada elemento

let dobrados: Vec&lt;i32&gt; = numeros

.iter()

.map(|x| x * 2)

.collect();

println!(&quot;{:?}&quot;, dobrados); // [2, 4, 6, 8, 10]

}</code></pre>

<h3>Filter: Selecionando Elementos</h3>

<p>O <code>filter</code> retorna um iterador contendo apenas elementos que satisfazem uma condição (predicado). Como o <code>map</code>, ele também é lazy e não consome memória desnecessária. A combinação de <code>filter</code> com <code>map</code> é extremamente comum em Rust para operações de processamento de dados. O <code>filter</code> recebe uma closure que retorna um booleano, e mantém apenas elementos onde a condição é <code>true</code>.</p>

<pre><code class="language-rust">fn main() {

let numeros = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Filter seleciona pares

let pares: Vec&lt;i32&gt; = numeros

.iter()

.filter( | x | x % 2 == 0) .map(|x| x 10)

.collect();

println!(&quot;{:?}&quot;, pares); // [20, 40, 60, 80, 100]

}</code></pre>

<h3>Fold: Acumulando Resultados</h3>

<p>O <code>fold</code> (também conhecido como <code>reduce</code>) é um consumidor que reduz um iterador a um único valor, acumulando resultados através de uma função. Diferente de <code>map</code> e <code>filter</code>, o <code>fold</code> <strong>consome</strong> o iterador e exige um valor inicial (acumulador). É a ferramenta ideal para cálculos como somas, produtos, concatenações ou qualquer agregação de dados. O <code>fold</code> recebe dois parâmetros: o acumulador inicial e uma closure que recebe o acumulador e o elemento atual.</p>

<pre><code class="language-rust">fn main() {

let numeros = vec![1, 2, 3, 4, 5];

// Fold calcula a soma

let soma = numeros

.iter()

.fold(0, |acum, x| acum + x);

println!(&quot;{}&quot;, soma); // 15

// Fold com strings

let palavras = vec![&quot;Rust&quot;, &quot;é&quot;, &quot;incrível&quot;];

let frase = palavras

.iter()

.fold(String::new(), |mut acum, palavra| {

if !acum.is_empty() {

acum.push(&#039; &#039;);

}

acum.push_str(palavra);

acum

});

println!(&quot;{}&quot;, frase); // &quot;Rust é incrível&quot;

}</code></pre>

<h2>Lazy Evaluation: O Segredo da Performance</h2>

<h3>Como Funciona a Avaliação Preguiçosa</h3>

<p>A lazy evaluation é o conceito chave que torna os iteradores em Rust tão eficientes. Quando você chama <code>map</code> ou <code>filter</code>, nenhuma operação acontece imediatamente. Estes adaptadores retornam novos iteradores que especificam <em>como</em> transformar os dados, mas não executam a transformação até que o iterador seja consumido por um método terminal como <code>collect()</code>, <code>fold()</code>, ou um loop <code>for</code>. Isso significa que você pode criar pipelines complexos com múltiplas transformações e Rust otimizará tudo junto, evitando alocações de memória intermediárias.</p>

<pre><code class="language-rust">fn main() {

let numeros = vec![1, 2, 3, 4, 5];

// Nada acontece aqui ainda!

let _resultado = numeros

.iter()

.filter( | x | x &gt; 2) .map(|x| x 2);

// Só aqui o iterador é consumido e processado

let vetor_final: Vec&lt;i32&gt; = numeros

.iter()

.filter( | x | x &gt; 2) .map(|x| x 2)

.collect();

println!(&quot;{:?}&quot;, vetor_final); // [6, 8, 10]

}</code></pre>

<h3>Exemplo Prático: Pipeline Complexo</h3>

<p>A combinação de lazy evaluation com múltiplos adaptadores cria código expressivo e performático. No exemplo abaixo, Rust analisa todo o pipeline e o otimiza em uma única passagem pelos dados, sem criar vetores intermediários. Este é um padrão extremamente comum em processamento de dados em Rust e demonstra por que a linguagem é tão eficiente.</p>

<pre><code class="language-rust">fn main() {

let dados = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let resultado: i32 = dados

.iter()

.filter( | x | x % 2 == 0) // Filtra pares .map(|x| x x) // Eleva ao quadrado .fold(0, |acum, x| acum + x); // Soma tudo

// Uma única passagem, sem alocações intermediárias

println!(&quot;Resultado: {}&quot;, resultado); // 4 + 16 + 36 + 100 = 156

}</code></pre>

<h2>Conclusão</h2>

<p>Dominar iteradores em Rust é fundamental para escrever código idiomático e eficiente. Os três pontos principais aprendidos foram: <strong>(1)</strong> <code>map</code> e <code>filter</code> são adaptadores lazy que transformam e selecionam elementos sem consumir memória extra, enquanto <code>fold</code> é um consumidor que reduz dados a um único valor; <strong>(2)</strong> lazy evaluation permite que Rust otimize pipelines complexos em uma única passagem, eliminando alocações intermediárias e tornando o código performático por padrão; <strong>(3)</strong> a combinação destes operadores cria código funcional, expressivo e seguro, que é testável e fácil de manter. Pratique combinando estes adaptadores em seus projetos e você verá como eles se tornam naturais e poderosos.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://doc.rust-lang.org/book/ch13-00-functional-features.html" target="_blank" rel="noopener noreferrer">The Rust Programming Language - Chapter 13: Functional Language Features</a></li>

<li><a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html" target="_blank" rel="noopener noreferrer">Rust Documentation - std::iter::Iterator</a></li>

<li><a href="https://blog.rust-lang.org/2015/05/11/traits.html" target="_blank" rel="noopener noreferrer">Iterators in Rust - Official Rust Blog</a></li>

<li><a href="https://doc.rust-lang.org/rust-by-example/fn/closures/iter_any.html" target="_blank" rel="noopener noreferrer">Rust by Example - Iterators</a></li>

<li><a href="https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/" target="_blank" rel="noopener noreferrer">Programming Rust: Fast, Safe Systems Development (Blandy &amp; Orendorff)</a></li>

</ul>

Comentários

Mais em Rust

Como Usar Workspaces no Cargo: Organizando Projetos Grandes em Rust em Produção
Como Usar Workspaces no Cargo: Organizando Projetos Grandes em Rust em Produção

O que são Workspaces no Cargo? Um workspace no Cargo é um mecanismo para orga...

O que Todo Dev Deve Saber sobre WebAssembly com Rust: Compilando para o Navegador com wasm-pack
O que Todo Dev Deve Saber sobre WebAssembly com Rust: Compilando para o Navegador com wasm-pack

Introdução ao WebAssembly com Rust WebAssembly (WASM) é um formato binário qu...

O que Todo Dev Deve Saber sobre Testes Unitários e de Integração em Rust com cargo test
O que Todo Dev Deve Saber sobre Testes Unitários e de Integração em Rust com cargo test

Fundamentos de Testes em Rust Testes em Rust são nativos à linguagem e totalm...