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); }