Some addendum regarding the code in question and the simple question of why it doesn’t compile, the compile gives some good first steps of explanation:
fn main()
{
let numbers = Vec::from_iter(0..=99);
let t = thread::spawn( move ||
{
let len = numbers.len();
let sum: i32 = numbers.into_iter().sum();
sum as f32/len as f32
});
let average = t.join().unwrap();
println!("The average is {}", average);
println!("{:?}", numbers);
}
Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `numbers`
--> src/main.rs:16:22
|
3 | let numbers = Vec::from_iter(0..=99);
| ------- move occurs because `numbers` has type `Vec<i32>`, which does not implement the `Copy` trait
4 |
5 | let t = thread::spawn( move ||
| ------- value moved into closure here
6 | {
7 | let len = numbers.len();
| ------- variable moved due to use in closure
...
16 | println!("{:?}", numbers);
| ^^^^^^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0382`.
So the error right now has nothing to do with the type signature of thread::spawn
and its usage of F: 'static
bounds yet. The message that’s relevant is
variable moved due to use in closure
So numbers
is moved into the closure and thus into the other thread, because it’s used in the closure; the missing piece of information why a value used in this particular closure is always immediately moved (and not e.g. borrowed) then is that it’s a move
-closure! It’s written right there in the code
move ||
the Rust code for “please move absolutely everything that this closure uses into the closure”.
If we removed the move
keyword
…
let t = thread::spawn( ||
…
the error message changes slightly
error[E0382]: borrow of moved value: `numbers`
--> src/main.rs:16:22
|
3 | let numbers = Vec::from_iter(0..=99);
| ------- move occurs because `numbers` has type `Vec<i32>`, which does not implement the `Copy` trait
4 |
5 | let t = thread::spawn( ||
| -- value moved into closure here
...
8 | let sum: i32 = numbers.into_iter().sum();
| ------- variable moved due to use in closure
...
16 | println!("{:?}", numbers);
| ^^^^^^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0382`.
Now the explanation points to a different point inside the closure body and still says
variable moved due to use in closure
honestly, probably it wouldn’t be a bad idea if this error case came with slightly different wording. At least now it points to not just any usage, but – and that’s the relevant detail – it points to a usage of numbers
that moves the variable, a call to .into_iter()
, a function that moves and consumes its arguments. If a closure body moves a captured variable, then that variable is captured by-move (otherwise the closure would not have the necessary ownership to move the value as needed). If we change this place in the code to some by-reference access, e.g. .iter().sum()
instead of .into_iter().sum()
, the error message changes yet again:
error[E0373]: closure may outlive the current function, but it borrows `numbers`, which is owned by the current function
--> src/main.rs:5:28
|
5 | let t = thread::spawn( ||
| ^^ may outlive borrowed value `numbers`
6 | {
7 | let len = numbers.len();
| ------- `numbers` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:5:13
|
5 | let t = thread::spawn( ||
| _____________^
6 | | {
7 | | let len = numbers.len();
8 | | let sum: i32 = numbers.iter().sum();
9 | |
10 | | sum as f32/len as f32
11 | | });
| |__________^
help: to force the closure to take ownership of `numbers` (and any other referenced variables), use the `move` keyword
|
5 | let t = thread::spawn( move ||
| ++++
For more information about this error, try `rustc --explain E0373`.
Now finally, we get the error that appears due to the F: 'static
requirement in the function signature of thread::spawn
, as the error message points out, “function requires argument type to outlive
'static
”, pointing to the (argument of the) call to thread::spawn
. The rustc --explain
information on this error code also contains some further elaboration on this very kind of example of using thread::spawn
and potentially even .join()
, see the online version of this information here.