Fn, FnOnce, FnMut
Closures are backed by Fn
, FnOnce
and FnMut
traits.
#![allow(unused)] fn main() { pub trait Fn<Args>: FnMut<Args> { extern "rust-call" fn call(&self, args: Args) -> Self::Output; } pub trait FnMut<Args>: FnOnce<Args> { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } pub trait FnOnce<Args> { type Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } }
Fn
Trait
- can be called multiple times
- don't move captured values out of its body
- don't mutate captured values
- even might not capture any environment variables
FnMut
andFnOnce
are supertraits ofFn
and it can be used as a paramater where aFnMut
orFnOnce
is expected- is implemented automatically for closures which take immutable references to environment variables or don't capture anything at all
fn apply<F>(x : i32, invoker : F ) -> i32 where F : Fn(i32) -> i32 { invoker(x) } fn main() { let double = |x : i32| x * 2; println!("{:?}", apply(10, double)); }
FnOnce
Trait
- cannot be called multiple times
- is implemented automatically by closures that might consume the captured virables or moves the captured variables out of its body
fn apply<F>(invoker : F ) where F : FnOnce() -> String { println!("{:?}", invoker()); } fn main() { let magic_string = String::from("a kind of magic"); let closure = move || magic_string ; apply(closure); // closure cannot be called again // apply(closure); }
FnMut
Trait
- can be called multiple times
- don't move the captured variables out of closure body, but mutate them
fn apply<F>(mut invoker : F ) where F : FnMut(&str) -> () { invoker("abra"); } fn main() { let mut magic_string = String::from("a kind of magic"); let closure = |x: &str| { magic_string.push_str(x); println!("{:?}", magic_string); } ; apply(closure); }
Returning Closure
fn closure_factory(x: i32) -> Box<dyn Fn(i32) -> i32> { Box::new(move |y : i32| x + y) } fn main() { let c = closure_factory(10); println!("{:?}", c(20)); }