Why `i32` typed variable can be used after moving into closure while `String` typed variable can't be?

I am learning closure in Rust. Here is the code I wrote:

fn main()
{
    let name = String::new();
    let closure_mv = move ||{ println!("{}", name) };

    closure_mv();
    println!("{}", name);
}

The above code snippet won't compile because I am trying to use the name variable after it moved to closure. I understand it.

But this code snippet compiles.....

fn main()
{
    let x: i32 = 100; 
    let closure_mv = move ||{ println!("{}", x) };

    closure_mv();
    println!("{}", x);
}

The variable x is moved into the closure according to the closure definition, still, I can use x afterward. Why is that?

Thanks.

Short answer: i32 is Copy, hence it is not technically moved, while String is not, hence it is moved.
Even shorter answer: Please read the Rust book.

6 Likes

In case you're unfamiliar with it, the Copy trait is mentioned in the Book here, and has a documentation page here. If a type implements the Copy trait (which is something that i32 does and String doesn't), then any action that moves a variable of that type will instead be interpreted as “copying” the value instead. This is why despite the quite explicit nature of the move keyword, it’s still “only copying” the variable, and you can keep using it afterwards.

In case you’d be wondering if there’s a cost to this impossibility of “actually moving” a Copy type: The only thing that differentiates a “move” from a “copy” is that the former has the compiler enforce that the old moved-from value is no longer usable. Under the hood it does (essentially) the same kind of thing either way, whether you’re copying or moving.

7 Likes