Closures
https://doc.rust-lang.org/reference/expressions/closure-expr.html
You can think of a closure as an anonymous function implementing the trait(s) Fn, FnMut or FnOnce with some captured context.
Their parameters are a comma-separated list of names within a pair of pipes (|). They don't need curly braces, unless you want to have multiple statements.
fn for_each_planet<F>(f: F) where F: Fn(&'static str) { f("Earth"); f("Mars"); f("Jupiter"); } fn main() { for_each_planet(|planet| println!("Hello, {}", planet)); } // prints: // Hello, Earth // Hello, Mars // Hello, Jupiter
The borrow rules apply to them too:
fn for_each_planet<F>(f: F) where F: Fn(&'static str) { f("Earth"); f("Mars"); f("Jupiter"); } fn main() { let greeting = String::from("Good to see you"); for_each_planet(|planet| println!("{}, {}", greeting, planet)); // our closure borrows `greeting`, so it cannot outlive it }
An FnMut needs to be mutably borrowed to be called, so it can only be called once at a time.
This is legal:
fn foobar<F>(f: F) where F: Fn(i32) -> i32 { println!("{}", f(f(2))); } fn main() { foobar(|x| x * 2); } // output: 8
This isn't:
fn foobar<F>(mut f: F) where F: FnMut(i32) -> i32 { println!("{}", f(f(2))); // error: cannot borrow `f` as mutable more than once at a time } fn main() { foobar(|x| x * 2); }
FnOnce closures can only be called once at all. They exist because some closure move out variables that have been moved when captured:
fn foobar<F>(f: F) where F: FnOnce() -> String { println!("{}", f()); } fn main() { let s = String::from("alright"); foobar(move || s); // `s` was moved into our closure, and our // closures moves it to the caller by returning // it. Remember that `String` is not `Copy`. }
This is enforced naturally, as FnOnce closures need to be moved in order to be called.
Here's a closure with two arguments:
fn foobar<F>(x: i32, y: i32, is_greater: F) where F: Fn(i32, i32) -> bool { let (greater, smaller) = if is_greater(x, y) { (x, y) } else { (y, x) }; println!("{} is greater than {}", greater, smaller); } fn main() { foobar(32, 64, |x, y| x > y); }
Here's a closure ignoring both its arguments:
fn main() { foobar(32, 64, |_, _| panic!("Lalala, I am not listening!")); }
And here's a toilet closure:
fn main() { countdown(3, |_| ()); }
Called such because |_| () looks like a toilet.