Filtrar coleções é uma tarefa fundamental em qualquer linguagem. Rust oferece diversos métodos para filtrar dados de forma eficiente e expressiva, desde filter() em iteradores até retain() para modificação in-place. Nesta receita, você vai aprender todas as formas de filtrar vetores em Rust.
Dependências
Todas as funções de filtragem fazem parte da biblioteca padrão:
[package]
name = "receita-filtrar"
version = "0.1.0"
edition = "2021"
Código Completo
fn main() {
// =============================================
// 1. iter().filter() — filtragem com iterador
// =============================================
let numeros = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Filtrar números pares
let pares: Vec<&i32> = numeros.iter().filter(|&&x| x % 2 == 0).collect();
println!("Pares (referências): {:?}", pares);
// [2, 4, 6, 8, 10]
// Usar copied() para obter valores em vez de referências
let pares: Vec<i32> = numeros.iter().copied().filter(|&x| x % 2 == 0).collect();
println!("Pares (valores): {:?}", pares);
// Filtrar com into_iter() — consome o vetor original
let dados = vec![10, 25, 30, 45, 50];
let maiores_que_20: Vec<i32> = dados.into_iter().filter(|&x| x > 20).collect();
println!("Maiores que 20: {:?}", maiores_que_20);
// dados não pode mais ser usado aqui
// =============================================
// 2. retain() — filtragem in-place (modifica o vetor)
// =============================================
let mut frutas = vec!["banana", "abacaxi", "maçã", "ameixa", "abacate"];
// Manter apenas frutas que começam com 'a'
frutas.retain(|f| f.starts_with('a'));
println!("\nFrutas com 'a': {:?}", frutas);
// ["abacaxi", "ameixa", "abacate"]
let mut valores = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
valores.retain(|&x| x % 3 == 0); // manter múltiplos de 3
println!("Múltiplos de 3: {:?}", valores);
// [3, 6, 9]
// =============================================
// 3. filter_map() — filtrar e transformar ao mesmo tempo
// =============================================
let textos = vec!["42", "olá", "7", "mundo", "100", "abc"];
// Tentar converter para i32, mantendo apenas os que convertem
let numeros: Vec<i32> = textos
.iter()
.filter_map(|s| s.parse::<i32>().ok())
.collect();
println!("\nConvertidos: {:?}", numeros);
// [42, 7, 100]
// filter_map com lógica customizada
let nomes = vec!["Ana Silva", "Bia", "Carlos Souza Santos", ""];
let primeiros_nomes: Vec<&str> = nomes
.iter()
.filter_map(|nome| {
if nome.is_empty() {
None
} else {
Some(nome.split_whitespace().next().unwrap())
}
})
.collect();
println!("Primeiros nomes: {:?}", primeiros_nomes);
// ["Ana", "Bia", "Carlos"]
// =============================================
// 4. partition() — dividir em dois grupos
// =============================================
let numeros = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let (pares, impares): (Vec<i32>, Vec<i32>) = numeros
.iter()
.partition(|&&x| x % 2 == 0);
println!("\nPares: {:?}", pares);
println!("Ímpares: {:?}", impares);
// Particionar structs
#[derive(Debug)]
struct Tarefa {
titulo: String,
concluida: bool,
}
let tarefas = vec![
Tarefa { titulo: "Estudar Rust".into(), concluida: true },
Tarefa { titulo: "Fazer deploy".into(), concluida: false },
Tarefa { titulo: "Escrever testes".into(), concluida: true },
Tarefa { titulo: "Revisar PR".into(), concluida: false },
];
let (concluidas, pendentes): (Vec<&Tarefa>, Vec<&Tarefa>) = tarefas
.iter()
.partition(|t| t.concluida);
println!("\nConcluídas:");
for t in &concluidas {
println!(" [x] {}", t.titulo);
}
println!("Pendentes:");
for t in &pendentes {
println!(" [ ] {}", t.titulo);
}
// =============================================
// 5. Combinando filter com outros adaptadores
// =============================================
let palavras = vec!["Rust", "é", "rápido", "seguro", "e", "produtivo"];
// Filtrar palavras longas, converter para maiúsculas
let resultado: Vec<String> = palavras
.iter()
.filter(|p| p.len() > 3)
.map(|p| p.to_uppercase())
.collect();
println!("\nPalavras longas em maiúsculas: {:?}", resultado);
// ["RUST", "RÁPIDO", "SEGURO", "PRODUTIVO"]
// Filtrar, enumerar e coletar com índice
let numeros = vec![10, 5, 20, 3, 15, 8, 25];
let grandes: Vec<(usize, &i32)> = numeros
.iter()
.enumerate()
.filter(|(_, &v)| v > 10)
.collect();
println!("Maiores que 10 (com índice): {:?}", grandes);
// [(2, 20), (4, 15), (6, 25)]
// =============================================
// 6. take_while() e skip_while() — filtragem posicional
// =============================================
let dados = vec![2, 4, 6, 7, 8, 10, 12];
let enquanto_par: Vec<&i32> = dados.iter().take_while(|&&x| x % 2 == 0).collect();
println!("\ntake_while par: {:?}", enquanto_par);
// [2, 4, 6] — para no primeiro ímpar
let depois_impar: Vec<&i32> = dados.iter().skip_while(|&&x| x % 2 == 0).collect();
println!("skip_while par: {:?}", depois_impar);
// [7, 8, 10, 12] — pula todos os pares iniciais
// =============================================
// 7. Contar e verificar com predicados
// =============================================
let notas = vec![7.5, 8.0, 5.5, 9.0, 6.0, 4.5, 8.5];
let aprovados = notas.iter().filter(|&&n| n >= 6.0).count();
let reprovados = notas.iter().filter(|&&n| n < 6.0).count();
println!("\nAprovados: {} | Reprovados: {}", aprovados, reprovados);
// any() e all() — verificar predicados
let todos_passaram = notas.iter().all(|&n| n >= 6.0);
let algum_dez = notas.iter().any(|&n| n == 10.0);
println!("Todos aprovados? {} | Alguém tirou 10? {}", todos_passaram, algum_dez);
}
Saída do Programa
Pares (referências): [2, 4, 6, 8, 10]
Pares (valores): [2, 4, 6, 8, 10]
Maiores que 20: [25, 30, 45, 50]
Frutas com 'a': ["abacaxi", "ameixa", "abacate"]
Múltiplos de 3: [3, 6, 9]
Convertidos: [42, 7, 100]
Primeiros nomes: ["Ana", "Bia", "Carlos"]
Pares: [2, 4, 6, 8, 10]
Ímpares: [1, 3, 5, 7, 9]
Concluídas:
[x] Estudar Rust
[x] Escrever testes
Pendentes:
[ ] Fazer deploy
[ ] Revisar PR
Palavras longas em maiúsculas: ["RUST", "RÁPIDO", "SEGURO", "PRODUTIVO"]
Maiores que 10 (com índice): [(2, 20), (4, 15), (6, 25)]
take_while par: [2, 4, 6]
skip_while par: [7, 8, 10, 12]
Aprovados: 5 | Reprovados: 2
Todos aprovados? false | Alguém tirou 10? false
Quando Usar Cada Método
| Método | Modifica original | Uso |
|---|---|---|
filter() | Nao (cria novo) | Filtragem funcional com iteradores |
retain() | Sim (in-place) | Remover elementos do vetor sem criar cópia |
filter_map() | Nao | Filtrar e transformar em uma única operação |
partition() | Nao | Dividir coleção em dois grupos |
take_while() | Nao | Pegar elementos enquanto condição for verdadeira |
skip_while() | Nao | Pular elementos enquanto condição for verdadeira |
Veja Também
- Iterar Coleções em Rust — todos os adaptadores de iterador para combinar com filter
- Ordenar Vetor em Rust — ordene os resultados filtrados
- Usar HashMap em Rust — filtre entradas de um HashMap e colete em Vec
- Rust Cheatsheet — referência rápida de iteradores e adaptadores
- Glossário Rust: Iterator — entenda como os iteradores lazy funcionam por baixo dos panos
- Filtragem de slices em Zig — compare a abordagem de Zig para filtrar dados