Desafio Rust

Processador de números com closures

Enunciado

Implemente uma função processar que recebe um vetor de inteiros e duas closures: uma para filtrar (retorna bool) e outra para transformar (retorna i32). A função deve retornar um novo vetor com os elementos filtrados e transformados. Use move para capturar um multiplicador externo na closure de transformação.

Requisitos

  • A função processar deve aceitar F: Fn(i32) -> bool e G: Fn(i32) -> i32.
  • A closure de filtro deve selecionar números pares.
  • A closure de transformação deve multiplicar por um fator capturado com move.
  • O programa deve imprimir o vetor resultante.

Código inicial

fn processar<F, G>(v: Vec<i32>, filtro: F, transformar: G) -> Vec<i32>
where
    F: Fn(i32) -> bool,
    G: Fn(i32) -> i32,
{
    // Complete aqui: filtre e transforme
    vec![]
}

fn main() {
    let numeros = vec![1, 2, 3, 4, 5, 6];
    let fator = 10;
    // Complete aqui: defina as closures e chame processar
}

Saída esperada

[20, 40, 60]
Ver dica

Use v.into_iter().filter(|&x| filtro(x)).map(|x| transformar(x)).collect(). A closure de transformação pode ser move |x| x * fator.

Mostrar solução
fn processar<F, G>(v: Vec<i32>, filtro: F, transformar: G) -> Vec<i32>
where
    F: Fn(i32) -> bool,
    G: Fn(i32) -> i32,
{
    v.into_iter()
        .filter(|&x| filtro(x))
        .map(|x| transformar(x))
        .collect()
}

fn main() {
    let numeros = vec![1, 2, 3, 4, 5, 6];
    let fator = 10;

    // Closure de filtro: mantém apenas pares
    let eh_par = |x| x % 2 == 0;

    // Closure de transformação: move fator para dentro
    let multiplicar = move |x| x * fator;

    let resultado = processar(numeros, eh_par, multiplicar);
    println!("{:?}", resultado);
}

Passo a passo

  1. Definimos processar com dois parâmetros genéricos F e G, ambos closures.
  2. A função usa v.into_iter() para consumir o vetor e iterar por valor.
  3. .filter(|&x| filtro(x)) aplica a closure de filtro, mantendo apenas elementos que retornam true.
  4. .map(|x| transformar(x)) aplica a closure de transformação a cada elemento restante.
  5. .collect() coleta os resultados em um novo Vec<i32>.
  6. Em main, criamos eh_par que verifica se um número é par.
  7. Criamos multiplicar com move, capturando fator por valor.
  8. Chamamos processar e imprimimos o vetor resultante.

Por que funciona

A função processar aceita closures que implementam Fn, pois apenas as chama sem modificar o ambiente. A closure eh_par captura nada e é Fn. A closure multiplicar usa move para capturar fator por valor, tornando-se Fn também (pois não modifica fator). O uso de into_iter permite consumir o vetor original, evitando cópias desnecessárias.

Erros comuns

  • Esquecer o move na closure de transformação: fator seria emprestado, mas como processar pode chamar a closure várias vezes, o empréstimo imutável também funcionaria. No entanto, se fator fosse mutável ou se a closure precisasse de ownership, move é necessário.
  • Usar iter() em vez de into_iter(): iter() empresta os elementos, mas filter e map esperam valores; seria necessário desreferenciar. into_iter() simplifica.
  • Não declarar filtro e transformar como mut na assinatura: como são Fn, não precisam ser mutáveis, então está correto.

Outra forma de resolver

Poderia usar v.into_iter().filter(|x| filtro(*x)).map(transformar).collect(). A diferença é que filter recebe &i32, então precisamos desreferenciar. A versão com |&x| é mais idiomática.

Saída esperada

[20, 40, 60]