Da trilha de Rust Este conceito ainda não saiu como card do dia. ir para o card de hoje

Rust Funções Intermediário

Closures

Closures são funções anônimas que capturam variáveis do ambiente onde são definidas. Diferente de funções normais, elas podem acessar variáveis locais sem recebê-las como parâmetro. Em Rust, closures implementam uma das três traits: Fn, FnMut ou FnOnce, dependendo de como capturam e usam as variáveis.

A captura pode ser por empréstimo imutável (Fn), empréstimo mutável (FnMut) ou por movimento (FnOnce). O compilador infere automaticamente qual trait se aplica, mas você pode forçar o movimento com a palavra-chave move. Closures são amplamente usadas como argumentos para funções como map, filter e fold.

Entender as diferenças entre Fn, FnMut e FnOnce é essencial para escrever código genérico que aceita closures. A escolha da trait afeta como a closure pode ser chamada e quantas vezes.

Pontos-chave

  • Closures capturam variáveis do ambiente, funções não.
  • Fn empresta imutavelmente, FnMut empresta mutavelmente, FnOnce consome.
  • move força a captura por valor, útil para threads e retorno de closures.
  • Closures podem ser passadas como parâmetros usando generics ou trait objects (impl Fn ou Box<dyn Fn>).
  • O compilador infere a trait automaticamente, mas você pode explicitá-la.
closures.rs
fn aplicar<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
    f(x)
}

fn main() {
    // Closure que captura por empréstimo imutável (Fn)
    let fator = 3;
    let multiplicar = |x| x * fator;
    println!("3 * 5 = {}", multiplicar(5));

    // Closure que captura por empréstimo mutável (FnMut)
    let mut contador = 0;
    let mut incrementar = || {
        contador += 1;
        contador
    };
    println!("Contador: {}", incrementar());
    println!("Contador: {}", incrementar());

    // Closure que consome a variável (FnOnce) com move
    let texto = String::from("Olá");
    let consumir = move || println!("Texto: {}", texto);
    consumir();
    // texto não é mais acessível aqui

    // Passando closure como parâmetro
    let resultado = aplicar(|x| x + 10, 7);
    println!("Resultado: {}", resultado);
}

Exercícios

  1. 1
    Fácil

    Closure que soma um valor fixo

    Crie uma closure que captura uma variável base e retorna a soma de base com um argumento. Depois, use a função aplicar para chamar essa closure com o valor 5 e imprima o resultado.

    Resolver
  2. 2
    Médio

    Contador com FnMut

    Implemente uma função executar_duas_vezes que recebe uma closure mutável e a chama duas vezes, retornando a soma dos resultados. Use uma closure que incrementa um contador interno e retorna o novo valor. Imprima a soma final.

    Resolver
  3. 3
    Desafio

    Processador de números com closures

    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.

    Resolver

Continue estudando