Move Semantics

By default, whenever we assign a value to a variable, pass it to a function, or return it from a function, ownership is transferred.

fn main() {
    let name = String::from("Tim"); // String is owned by name

    greet(name);                    // Ownership is transferred
}

fn greet(name: String) {
    println!("Hello, {}!", name);
}

This example works fine, but note that when we return from greet, name is no longer accessible in main. It has been dropped because ownership was transferred to the name in greet, which went out of scope when the function completed.

If we tried to call it again, it would fail.

fn main() {
    let name = String::from("Tim"); // String is owned by name

    greet(name);                    // Ownership is transferred

    greet(name);                    // use of moved value: `name`
}

fn greet(name: String) {
    println!("Hello, {}!", name);
}

Note that this is a compile-time error. We never get a chance to run this. The full compiler message is

$ cargo run
   Compiling ownership v0.1.0 (/home/tim/rust/ownership)
error[E0382]: use of moved value: `name`
 --> src/main.rs:5:11
  |
2 |     let name = String::from("Tim");
  |         ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait
3 | 
4 |     greet(name);
  |           ---- value moved here
5 |     greet(name);
  |           ^^^^ value used here after move

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
error: could not compile `ownership`

To learn more, run the command again with --verbose.

Note the message, "move occurs because name has type String, which does not implement the Copy trait." That gives us a hint how we could fix this. If we make a copy of our string (String types have a clone method which does exactly this), then we could move that while retaining the original.

fn main() {
    let name = String::from("Tim"); // String is owned by name

    greet(name.clone());            // Make a copy and move that

    greet(name);                    // Original is still available
}

fn greet(name: String) {
    println!("Hello, {}!", name);
}