Closures

Closures ou expressĂ”es lambda tĂȘm tipos que nĂŁo podem ser nomeados. No entanto, eles implementam os traits especiais Fn, FnMut e FnOnce:

fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {
    println!("Calling function on {input}");
    func(input)
}

fn main() {
    let add_3 = |x| x + 3;
    println!("add_3: {}", apply_with_log(add_3, 10));
    println!("add_3: {}", apply_with_log(add_3, 20));

    let mut v = Vec::new();
    let mut accumulate = |x: i32| {
        v.push(x);
        v.iter().sum::<i32>()
    };
    println!("accumulate: {}", apply_with_log(&mut accumulate, 4));
    println!("accumulate: {}", apply_with_log(&mut accumulate, 5));

    let multiply_sum = |x| x * v.into_iter().sum::<i32>();
    println!("multiply_sum: {}", apply_with_log(multiply_sum, 3));
}

Um Fn nĂŁo consome nem muda os valores capturados ou talvez nĂŁo capture nada, entĂŁo, pode ser chamado vĂĄrias vezes simultaneamente.

Um FnMut pode alterar os valores capturados, entĂŁo vocĂȘ pode chamĂĄ-lo vĂĄrias vezes, mas nĂŁo simultaneamente.

Se vocĂȘ tiver um FnOnce, poderĂĄ chamĂĄ-lo apenas uma vez. Pode consumir os valores capturados.

FnMut Ă© um subtipo de FnOnce. Fn Ă© um subtipo de FnMut e FnOnce. Ou seja vocĂȘ pode usar um FnMut sempre que um FnOnce Ă© chamado e vocĂȘ pode usar um Fn sempre que um FnMut ou um FnOnce Ă© chamado.

The compiler also infers Copy (e.g. for add_3) and Clone (e.g. multiply_sum), depending on what the closure captures.

By default, closures will capture by reference if they can. The move keyword makes them capture by value.

fn make_greeter(prefix: String) -> impl Fn(&str) {
    return move |name| println!("{} {}", prefix, name)
}

fn main() {
    let hi = make_greeter("Hi".to_string());
    hi("there");
}