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"); }