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)