Programação Funcional em Rust: Nível Avançado
\n\nRust é uma linguagem multiparadigma que combina organicamente estilos imperativo, orientado a objetos e funcional. Em nível avançado, a programação funcional em Rust permite escrever código mais seguro, expressivo e conciso. Neste artigo, vamos explorar conceitos-chave: closures com captura de ambiente, iteradores avançados, functores e mônadas usando Option e Result, além de currying e composição de funções.
1. Closures: Propriedade, Empréstimo e Mutabilidade
\n\nClosures em Rust não são apenas funções anônimas. Elas podem capturar variáveis do escopo circundante de três maneiras: por referência (&T), por referência mutável (&mut T) e por valor (T). O compilador escolhe automaticamente a trait menos restritiva: Fn, FnMut ou FnOnce.
Veja um exemplo com captura por valor e uso de move:
fn main() {\n let data = vec![1, 2, 3];\n \n // Captura por valor (move) — a propriedade é transferida para a closure\n let closure = move || {\n println!("{:?}", data);\n // data não está mais disponível na função principal\n };\n \n closure();\n // println!("{:?}", data); // Erro: data foi movida\n}\n\n\nUma técnica avançada é usar closures para criar fábricas de funções:
\n\nfn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {\n move |x| x * factor\n}\n\nfn main() {\n let double = make_multiplier(2);\n let triple = make_multiplier(3);\n \n println!("{}", double(5)); // 10\n println!("{}", triple(5)); // 15\n}\n\n\nAqui, impl Fn(i32) -> i32 é o tipo de retorno da closure. Rust gera automaticamente um tipo anônimo que implementa a trait Fn.
2. Iteradores Avançados: Cadeias, Adaptadores e Computação Preguiçosa
\n\nIteradores em Rust são uma ferramenta poderosa do estilo funcional. Eles são preguiçosos: os cálculos ocorrem apenas quando um método terminal é chamado (collect, for_each, fold, etc.).
Veja um pipeline complexo de processamento de dados:
\n\nfn process_data(data: Vec<i32>) -> Vec<i32> {\n data.iter()\n .filter(|&x| x > 0) // Mantém apenas positivos\n .map(|x| x * 2) // Dobra\n .enumerate() // Adiciona índices\n .filter(|(i, _)| i % 2 == 0) // Índices pares\n .map(|(_, x)| x) // Extrai o valor\n .collect() // Método terminal\n}\n\n\nUma técnica avançada é usar flat_map para trabalhar com estruturas aninhadas e fold para acumulação:
fn main() {\n let nested = vec![vec![1, 2], vec![3, 4, 5], vec![6]];\n \n let flattened: Vec<i32> = nested.iter()\n .flat_map(|v| v.iter())\n .copied()\n .collect();\n \n println!("{:?}", flattened); // [1, 2, 3, 4, 5, 6]\n \n // fold — análogo funcional ao reduce\n let sum = flattened.iter()\n .fold(0, |acc, x| acc + x);\n \n println!("Soma: {}", sum); // 21\n}\n\n\nÉ importante lembrar: cadeias de iteradores não criam coleções intermediárias se collect não for chamado. Isso economiza memória e melhora o desempenho.
3. Mônadas Option e Result: Tratamento Funcional de Erros
\n\nNa programação funcional, Option e Result são mônadas. Elas permitem processar valores opcionais e erros em cadeia, sem a necessidade de match ou if let aninhados.
Veja um cenário típico com verificações aninhadas:
\n\nBlogs
Book Recommendations
Leia também
Sockets em Python: guia completo para iniciantes e experts
Como mover arquivos e trabalhar com diretórios em Python
DateTime em ISO 8601 em C#: guia completo com respostas para perguntas frequentes
PHP para aprendizado de máquina: possibilidades e limitações na prática
== vs === em PHP: qual a diferença e por que isso importa?