4.3 rust func closure
fn add_one_v1 (x: u32) -> u32 { x + 1 } let add_one_v2 = |x: u32| -> u32 { x + 1 }; let add_one_v3 = |x| { x + 1 }; let add_one_v4 = |x| x + 1 ;
pub fn test3() { let example_closure = |x| x; let s = example_closure(String::from("hello")); let n = example_closure(5); }
--> src/base/k_closure.rs:53:29 | 53 | let n = example_closure(5); | ^ | | | expected struct `String`, found integer | help: try using a conversion method: `5.to_string()`
The first time we call example_closure
with the String
value, the compiler infers the type of x
and the return type of the closure to be String
. Those types are then locked into the closure in example_closure
, and we get a type error if we try to use a different type with the same closure.
不换数据类型,下面的是正确的
pub fn test3() { let example_closure = |x| x; let s = example_closure(6); println!("{}",s); let n = example_closure(5); println!("{}",n); }
6 5
Capturing the Environment with Closures
fn main() { let x = 4; let equal_to_x = |z| z == x; let y = 4; assert!(equal_to_x(y)); }
Here, even though x
is not one of the parameters of equal_to_x
, the equal_to_x
closure is allowed to use the x
variable that’s defined in the same scope that equal_to_x
is defined in.
Closures can capture values from their environment in three ways, which directly map to the three ways a function can take a parameter: taking ownership, borrowing mutably, and borrowing immutably. These are encoded in the three Fn
traits as follows:
FnOnce
consumes the variables it captures from its enclosing scope, known as the closure’s environment. To consume the captured variables, the closure must take ownership of these variables and move them into the closure when it is defined. TheOnce
part of the name represents the fact that the closure can’t take ownership of the same variables more than once, so it can be called only once.FnMut
can change the environment because it mutably borrows values.Fn
borrows values from the environment immutably.
When you create a closure, Rust infers which trait to use based on how the closure uses the values from the environment. All closures implement FnOnce
because they can all be called at least once. Closures that don’t move the captured variables also implement FnMut
, and closures that don’t need mutable access to the captured variables also implement Fn
. In Listing 13-12, the equal_to_x
closure borrows x
immutably (so equal_to_x
has the Fn
trait) because the body of the closure only needs to read the value in x
.
If you want to force the closure to take ownership of the values it uses in the environment, you can use the move
keyword before the parameter list. This technique is mostly useful when passing a closure to a new thread to move the data so it’s owned by the new thread.
Note: move closures may still implement Fn or FnMut, even though they capture variables by move. This is because the traits implemented by a closure type are determined by what the closure does with captured values, not how it captures them. The move keyword only specifies the latter.