In Rust, there's two kinds of types.
Types that implement the Copy
trait, and types that don't.
When you pass a Copy
type to a function, you can still use it.
let u32_is_Copy = 100u32;
fn function_that_takes_a_u32(u32_is_Copy);
// You can still use the value here!
println!("{}", u32_is_Copy);
Copy
types are types that can be bit-wise copied when they need to be used somewhere in the program. This is the case for types for bool
, u64
, and all the common integer types.
But some types are not Copy
. They cannot be copied trivally.
let Vec_is_not_Copy = vec![0, 1, 2];
fn function_that_takes_a_Vec(Vec_is_not_Copy);
// This doesn't work! The ownership of `Vec_is_not_Copy` has been given
// to the function. We are not allowed to use it anymore.
println!("{}", Vec_is_not_Copy);
Passing values to closures is the same exact thing. When you use a u32
, its value is copied because u32: Copy
. When you use a Vec<T>
, it is moved, because Vec<T>: !Copy
.
In other words, the Copy
trait enables you to opt-out of Rust's ownership rules. Implementing Copy
for a type is like saying to the compiler: "instances of this type do not carry any special meaning, they are just raw bytes".
The code you provided works fine without the move
keyword because it's like you tried to call the functions by passing the values by reference.
fn function_that_takes_a_u32(&u32_is_Copy);
fn function_that_takes_a_Vec(&Vec_is_not_Copy);
In that case, both values can still be used. What have been copied to the function is a &u32
and &Vec
respectively. Note that &T
is Copy
for any T
.
// This works!
println!("{}", u32_is_Copy);
println!("{}", Vec_is_not_Copy);