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!("Chamando a função com {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
(p.ex. add_3
) nĂŁo consome nem muda os valores capturados ou talvez nĂŁo capture nada, podendo entĂŁo ser chamado vĂĄrias vezes simultaneamente.
Um FnMut
(p.ex. accumulate
) pode alterar os valores capturados, logo vocĂȘ pode chamĂĄ-lo vĂĄrias vezes, mas nĂŁo simultaneamente.
Se vocĂȘ tiver um FnOnce
(p.ex. multiply_sum
), poderĂĄ chamĂĄ-lo apenas uma vez. Ele 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.
Quando vocĂȘ define uma função que recebe um closure, vocĂȘ deve usar FnOnce
se puder (ou seja, vocĂȘ o chama uma vez) ou FnMut
caso contrĂĄrio, e por Ășltimo Fn
. Isso permite a maior flexibilidade para o chamador.
Em contraste, quando vocĂȘ tem um closure, o mais flexĂvel que vocĂȘ pode ter Ă© Fn
(ele pode ser passado para qualquer lugar), entĂŁo FnMut
e, por Ășltimo, FnOnce
.
O compilador também infere Copy
(p.ex. para add_3
) e Clone
(p.ex.
Por padrĂŁo, os closures capturam por referĂȘncia se puderem. A palavra-chave move
faz com que eles capturem por valor.
fn make_greeter(prefix: String) -> impl Fn(&str) { return move |name| println!("{} {}", prefix, name); } fn main() { let hi = make_greeter("OlĂĄ".to_string()); hi("Greg"); }