From 21ee7df745fc70dfcec8d3e87070240cdfb03dbf Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Wed, 31 May 2017 13:58:52 -0400 Subject: [PATCH] Add a small example of a `move` closure Fixes #610. --- second-edition/src/ch13-01-closures.md | 52 ++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/second-edition/src/ch13-01-closures.md b/second-edition/src/ch13-01-closures.md index ba5a69052..6ed090e4e 100644 --- a/second-edition/src/ch13-01-closures.md +++ b/second-edition/src/ch13-01-closures.md @@ -859,10 +859,54 @@ values are encoded in the three `Fn` traits as follows: * `Fn` borrows values from the environment immutably * `FnMut` can change the environment since it mutably borrows values -Creating `FnOnce` closures that capture values from their environment is mostly -used in the context of starting new threads. We'll show some examples and -explain more detail about this feature of closures in Chapter 16 when we talk -about concurrency. +When we create a closure, Rust infers how we want to reference the environment +based on how the closure uses the values from the environment. In Listing +13-12, the `equal_to_x` closure borrows `x` immutably (so `equal_to_x` has the +`Fn` trait) since the body of the closure only needs to read the value in `x`. + +If we want to force the closure to take ownership of the values it uses in the +environment, we can use the `move` keyword before the parameter list. This is +mostly useful when passing a closure to a new thread in order to move the data +to be owned by the new thread. We'll have more examples of `move` closures in +Chapter 16 when we talk about concurrency, but for now here's the code from +Listing 13-12 with the `move` keyword added to the closure definition and using +vectors instead of integers, since integers can be copied rather than moved: + +Filename: src/main.rs + +```rust +fn main() { + let x = vec![1, 2, 3]; + + let equal_to_x = move |z| z == x; + + println!("can't use x here: {:?}", x); + + let y = vec![1, 2, 3]; + + assert!(equal_to_x(y)); +} +``` + +This example doesn't compile: + +```text +error[E0382]: use of moved value: `x` + --> src/main.rs:6:40 + | +4 | let equal_to_x = move |z| z == x; + | -------- value moved (into closure) here +5 | +6 | println!("can't use x here: {:?}", x); + | ^ value used here after move + | + = note: move occurs because `x` has type `std::vec::Vec`, which does not + implement the `Copy` trait +``` + +The `x` value is moved into the closure when the closure is defined because of +the `move` keyword. The closure then has ownership of `x`, and `main` isn't +allowed to use `x` anymore. Removing the `println!` will fix this example. Most of the time when specifying one of the `Fn` trait bounds, you can start with `Fn` and the compiler will tell you if you need `FnMut` or `FnOnce` based