Closure
This is the 6th day and I almost gave up because this "closure" thing is so complicated.
You can see this article here: Why Rust Closures are (Somewhat) Hard
But finally I think I (somewhat) got it (or I hope so).
General use case
fn main() {
let num_vec = vec![1,2,3,4,5,6];
let num_arr = [1,2,3,4,5,6];
let finder = |x: &&i32| **x==3;
let found_in_vec = num_vec.iter().find(finder)
.unwrap();
let found_in_arr = num_arr.iter().find(finder)
.unwrap();
println!("found in vec: {}", found_in_vec);
println!("found in arr: {}", found_in_arr);
// Pass closure to filter
let filtered: Vec<&i32> = num_vec.iter()
.filter(|&&x| x % 3 == 0)
.collect();
println!("Filtered: {:?}", filtered);
// FizzBuzz
println!("{}", "=".repeat(20));
let numbers: Vec<i32> = (1..31).collect();
numbers.iter().for_each(|x| {
if x % 15 == 0 {
println!("Fizz Buzz");
} else if x % 3 == 0 {
println!("Fizz");
} else if x % 5 == 0 {
println!("Buzz");
} else {
println!("{}", x);
}
});
// Found all numbers divisible by 3
let div3: Vec<&i32> = numbers.iter()
.filter(|&&x| x % 3 == 0)
.collect();
println!("Div3: {:?}", div3);
// map a function to range
let doubled:Vec<i32> = (1..10).map(|x| x*2).collect();
println!("Doubled: {:?}", doubled);
// sum all even numbers b/t 1 to 10 (10 is not included)
let sum:i32 = (1..10).filter(|x| x % 2 == 0).sum();
println!("Sum is {}", sum);
}
Result
found in vec: 3
found in arr: 3
Filtered: [3, 6]
====================
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
Fizz Buzz
Div3: [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
Doubled: [2, 4, 6, 8, 10, 12, 14, 16, 18]
Sum is 20
Closure as input: Fn, FnMut, FnOnce
How variables are captured (by &, by &mut or by value) won't determine which trait (Fn, FnMut, FnOnce) will be used by compiler.
For example, when you use move
, the variable is captured by value, but if that value is only being used for read, compiler will still use Fn
attribute, not FnOnce
, but if that variable is dropped, then compiler will use FnOnce
fn apply<F>(f: F) where F: FnOnce() {
f();
}
fn sayhi() {
println!("hi");
}
fn main() {
let greeting = "hello";
let mut copied = greeting.to_owned();
let say = || {
// If just this one line,
// F could be Fn, FnMut and FnOnce
println!("{}", greeting);
// With this line, F cannot be Fn anymore
// needs to be FnMut or FnOnce
copied.push_str(" world");
// with this line, F needs to be FnOnce
drop(copied);
};
apply(say);
apply(sayhi);
}
Result:
hello
hi
Closure as output (returned)
fn create_fn() -> impl Fn() {
let text = "Fn".to_owned();
move || println!("This is a: {}", text)
}
fn create_fnmut() -> impl FnMut() {
let text = "FnMut".to_owned();
move || println!("This is a: {}", text)
}
fn main() {
let fn_plain = create_fn();
let mut fn_mut = create_fnmut();
fn_plain();
fn_mut();
}
Result:
This is a: Fn
This is a: FnMut
Top comments (0)