mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-05-14 14:46:43 +02:00
Clarify Fn traits slide (#2333)
Improve naming and always capture something in our closures; explain other details/variations in speaker notes. Fixes #2251.
This commit is contained in:
parent
432f7bc5dc
commit
b3adc3b09a
@ -10,39 +10,41 @@ implement special [`Fn`](https://doc.rust-lang.org/std/ops/trait.Fn.html),
|
|||||||
[`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) traits:
|
[`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) traits:
|
||||||
|
|
||||||
```rust,editable
|
```rust,editable
|
||||||
fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {
|
fn apply_and_log(func: impl FnOnce(i32) -> i32, func_name: &str, input: i32) {
|
||||||
println!("Calling function on {input}");
|
println!("Calling {func_name}({input}): {}", func(input))
|
||||||
func(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let add_3 = |x| x + 3;
|
let n = 3;
|
||||||
println!("add_3: {}", apply_with_log(add_3, 10));
|
let add_3 = |x| x + n;
|
||||||
println!("add_3: {}", apply_with_log(add_3, 20));
|
apply_and_log(&add_3, "add_3", 10);
|
||||||
|
apply_and_log(&add_3, "add_3", 20);
|
||||||
|
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
let mut accumulate = |x: i32| {
|
let mut accumulate = |x: i32| {
|
||||||
v.push(x);
|
v.push(x);
|
||||||
v.iter().sum::<i32>()
|
v.iter().sum::<i32>()
|
||||||
};
|
};
|
||||||
println!("accumulate: {}", apply_with_log(&mut accumulate, 4));
|
apply_and_log(&mut accumulate, "accumulate", 4);
|
||||||
println!("accumulate: {}", apply_with_log(&mut accumulate, 5));
|
apply_and_log(&mut accumulate, "accumulate", 5);
|
||||||
|
|
||||||
let multiply_sum = |x| x * v.into_iter().sum::<i32>();
|
let multiply_sum = |x| x * v.into_iter().sum::<i32>();
|
||||||
println!("multiply_sum: {}", apply_with_log(multiply_sum, 3));
|
apply_and_log(multiply_sum, "multiply_sum", 3);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
An `Fn` (e.g. `add_3`) neither consumes nor mutates captured values, or perhaps
|
An `Fn` (e.g. `add_3`) neither consumes nor mutates captured values. It can be
|
||||||
captures nothing at all. It can be called multiple times concurrently.
|
called needing only a shared reference to the closure, which means the closure
|
||||||
|
can be executed repeatedly and even concurrently.
|
||||||
|
|
||||||
An `FnMut` (e.g. `accumulate`) might mutate captured values. You can call it
|
An `FnMut` (e.g. `accumulate`) might mutate captured values. The closure object
|
||||||
multiple times, but not concurrently.
|
is accessed via exclusive reference, so it can be called repeatedly but not
|
||||||
|
concurrently.
|
||||||
|
|
||||||
If you have an `FnOnce` (e.g. `multiply_sum`), you may only call it once. It
|
If you have an `FnOnce` (e.g. `multiply_sum`), you may only call it once. Doing
|
||||||
might consume captured values.
|
so consumes the closure and any values captured by move.
|
||||||
|
|
||||||
`FnMut` is a subtype of `FnOnce`. `Fn` is a subtype of `FnMut` and `FnOnce`.
|
`FnMut` is a subtype of `FnOnce`. `Fn` is a subtype of `FnMut` and `FnOnce`.
|
||||||
I.e. you can use an `FnMut` wherever an `FnOnce` is called for, and you can use
|
I.e. you can use an `FnMut` wherever an `FnOnce` is called for, and you can use
|
||||||
@ -52,14 +54,17 @@ When you define a function that takes a closure, you should take `FnOnce` if you
|
|||||||
can (i.e. you call it once), or `FnMut` else, and last `Fn`. This allows the
|
can (i.e. you call it once), or `FnMut` else, and last `Fn`. This allows the
|
||||||
most flexibility for the caller.
|
most flexibility for the caller.
|
||||||
|
|
||||||
In contrast, when you have a closure, the most flexible you can have is `Fn` (it
|
In contrast, when you have a closure, the most flexible you can have is `Fn`
|
||||||
can be passed everywhere), then `FnMut`, and lastly `FnOnce`.
|
(which can be passed to a consumer of any of the 3 closure traits), then
|
||||||
|
`FnMut`, and lastly `FnOnce`.
|
||||||
|
|
||||||
The compiler also infers `Copy` (e.g. for `add_3`) and `Clone` (e.g.
|
The compiler also infers `Copy` (e.g. for `add_3`) and `Clone` (e.g.
|
||||||
`multiply_sum`), depending on what the closure captures.
|
`multiply_sum`), depending on what the closure captures. Function pointers
|
||||||
|
(references to `fn` items) implement `Copy` and `Fn`.
|
||||||
|
|
||||||
By default, closures will capture by reference if they can. The `move` keyword
|
By default, closures will capture each variable from an outer scope by the least
|
||||||
makes them capture by value.
|
demanding form of access they can (by shared reference if possible, then
|
||||||
|
exclusive reference, then by move). The `move` keyword forces capture by value.
|
||||||
|
|
||||||
```rust,editable
|
```rust,editable
|
||||||
fn make_greeter(prefix: String) -> impl Fn(&str) {
|
fn make_greeter(prefix: String) -> impl Fn(&str) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user