Programação Funcional em Rust: Técnicas e Idiomas Avançados

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
```html

Programação Funcional em Rust: Nível Avançado



Rust é uma linguagem multiparadigma que combina organicamente abordagens imperativas e funcionais. Para desenvolvedores já familiarizados com os fundamentos do Rust, abre-se um mundo de técnicas funcionais avançadas que permitem escrever código mais conciso, seguro e expressivo. Neste artigo, exploraremos conceitos-chave de programação funcional (FP) em nível avançado: desde o uso profundo de closures e iterators até composição de funções e emulação de monads.



1. Closures Avançadas: Propriedade, Empréstimo e Traits



Closures em Rust não são apenas funções anônimas. O compilador implementa automaticamente para elas um dos traits: Fn, FnMut ou FnOnce. Entender como uma closure captura variáveis do ambiente é crucial para escrever código eficiente.



Captura com movimentação (move closure) é usada quando a closure precisa ser proprietária dos dados capturados, por exemplo, ao ser enviada para uma nova thread:



use std::thread;

let data = vec![1, 2, 3];

let handle = thread::spawn(move || { println!("{:?}", data); // data movida para a closure});

handle.join().unwrap();


Closures como argumentos de funções permitem criar APIs flexíveis. Use tipos genéricos com trait bounds:



fn apply_twice<F>(f: F, x: i32) -> i32where    F: Fn(i32) -> i32,{    f(f(x))}

let square = |x| x * x;println!("{}", apply_twice(square, 2)); // Saída: 16


Retornar closures é uma tarefa complexa devido ao tamanho desconhecido do tipo da closure. Use Box<dyn Fn> ou a palavra-chave impl:



fn make_adder(x: i32) -> impl Fn(i32) -> i32 {    move |y| x + y}

let add_five = make_adder(5);println!("{}", add_five(10)); // 15


2. Iterators: Preguiça, Combinadores e Performance



Iterators em Rust são uma ferramenta funcional poderosa. Eles são preguiçosos: os cálculos ocorrem apenas quando um método terminal é chamado (ex.: collect(), for_each()).



Cadeias de combinadores permitem construir transformações complexas de dados sem loops:



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

let result: Vec<i32> = numbers .iter() .filter(|&&x| x % 2 == 0) // mantém os pares .map(|&x| x * 2) // multiplica por 2 .take(2) // pega os dois primeiros .collect();

println!("{:?}", result); // [4, 8]


Iterators personalizados são criados implementando o trait Iterator. Por exemplo, um iterator de números de Fibonacci:



struct Fibonacci {    curr: u64,    next: u64,}

impl Fibonacci { fn new() -> Self { Fibonacci { curr: 0, next: 1 } }}

impl Iterator for Fibonacci { type Item = u64;

fn next(&mut self) -> Option<Self::Item> { let new_next = self.curr.checked_add(self.next)?; self.curr = self.next; self.next = new_next; Some(self.curr) }}

let fib: Vec<u64> = Fibonacci::new().take(10).collect();println!("{:?}", fib); // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]


Performance dos iterators frequentemente não fica atrás dos loops manuais e, em alguns casos, o compilador LLVM gera código mais otimizado.



3. Composição de Funções e Estilo Monádico



Rust não possui composição de funções embutida, mas é fácil implementá-la. A composição permite construir novas funções a partir de funções existentes.



Composição simples com closures:



fn compose<F, G, A, B, C>(f: F, g: G) -> impl Fn(A) -> Cwhere    F: Fn(B) -> C,    G: Fn(A) -> B,{    move |x| f(g(x))}

let add_o ```

Blogs

Book Recommendations