Ownership and Moves

In Rust, all values have an owner. To check out ownership in action, we can create a String variable using a let binding (the keyword for a statement to create a variable in the current scope). Notice that we call .to_string() to convert the string literal (a &str) into a String, although we'll avoid discussing that until a bit later on.

fn main() {
    let _x: String = "Hello, World!".to_string();
}
Playground

We then own the value _x. In Rust, there can only be one owner of a variable at a time, so if we call a function that takes a String as a parameter and prints it out. Notice that println! is a variadic macro, and formats instances of {} in its first argument with its remaining arguments, similar to printf in C, although using curly braces instead of % symbols.

fn foo(bar: String) {
    println!("Got {}", bar);
}

fn main() {
    let x: String = "Hello, World!".to_string();
    foo(x);
}
Playground

We will move, or transfer ownership, of x to foo when we pass x to it as a parameter. If we then want to use the value x later in the main function, for example to print it out:

fn foo(bar: String) {
    println!("Got {}", bar);
}

fn main() {
    let x: String = "Hello, World!".to_string();
    foo(x);
    println!("X is {}", x);
}
Playground

You'll notice if you build or run this code in the Playground, we get a compile error:

   Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `x`
 --> src/main.rs:8:25
  |
6 |     let x: String = "Hello, World!".to_string();
  |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
7 |     foo(x);
  |         - value moved here
8 |     println!("X is {}", x);
  |                         ^ value borrowed here after move
  |
note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
 --> src/main.rs:1:13
  |
1 | fn foo(bar: String) {
  |    ---      ^^^^^^ this parameter takes ownership of the value
  |    |
  |    in this function
  = 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)
help: consider cloning the value if the performance cost is acceptable
  |
7 |     foo(x.clone());
  |          ++++++++

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` due to previous error

The error breaks down exactly what is happening here. main owned x when it was declared, but it transferred ownership of x to foo when it passed x to foo as a parameter. This means that when we try to use x in the println! statement we just added to main, main actually no longer owns x, so it is an error to try and use it!

This relationship is the core of how Rust ensures its safety guarantees, but may be surprising to experienced C/C++ programmers because those languages have no enforced concept of ownership of variables at all. There are a few ways to resolve this. The first is to do what the compiler suggests, and clone() the string. This creates a duplicate of the string in memory, and passes that duplicate to foo. This way, main retains ownership of x, and foo gets its own duplicate as a parameter. These are two different values, of course, but we are not modifying them so this is semantically equivalent.

fn foo(bar: String) {
    println!("Got {}", bar);
}

fn main() {
    let x: String = "Hello, World!".to_string();
    foo(x.clone());
    println!("X is {}", x);
}
Playground

If we run this, it'll succeed! However, we have made two tradeoffs. First, clone() isn't free, either in terms of memory space or compute cycles. Second, if we added code that modifies x in foo, main wouldn't print that modified value, it would print the initial value. In this example, note that we have added the mut keyword to the bar parameter in foo. This means this variable is mutable, so we can change it. If we didn't add mut, it would be a compile error to modify the value of bar in this function.

fn foo(mut bar: String) {
    bar += " I'm here!";
    println!("Got {}", bar);
}

fn main() {
    let x: String = "Hello, World!".to_string();
    foo(x.clone());
    println!("X is {}", x);
}
Playground

If we run this program in the Playground now, we'll see:

Got Hello, World! I'm here!
X is Hello, World!

This is, semantically, what we expect. foo modified its duplicate of x and printed out the duplicate, while main printed out the original value. But what if we wanted foo to modify the original value, instead? In C/C++, we'd pass a pointer to x to foo if we wanted to do that. Rust has a similar concept called a reference, and the act of creating a reference is called borrowing.