Moves and copies
Rust frees memory without a garbage collector. It does this with three simple rules about ownership.
The rules
- Every value has exactly one owner.
- When the owner goes out of scope, the value is dropped.
- Ownership can move to another variable, but there is still only one owner.
String::from("hi") makes a String: text that can grow. s.push('!') adds a char to its end, so s must be let mut.
A scope is the { } block a variable lives in. drop(x) drops a value right away, before its scope ends. After that, x can't be used.
Moves
A String or Vec keeps its data on the heap. Assigning it to another variable moves ownership:
let a = String::from("hi");let b = a; // ownership moves to bprintln!("{b}"); // fine// println!("{a}"); // error E0382: a was movedPassing a value to a function also moves it. Returning a value moves ownership back to the caller.
format! is handy for making a value to return. It works like println!, but gives back a new String instead of printing it.
fn shout(s: String) -> String { format!("{s}!")}Copies
Small types that live on the stack are copied instead of moved. These include integers, floats, bool, char, and tuples made only of them. After let y = x; with an i32, both x and y work.
A struct moves by default. It is copied only if it has #[derive(Clone, Copy)], and that needs every field to be Copy.
Clone
When you want two independent values, call .clone(). It copies the heap data too, so it can be slow for big values.
let a = String::from("hi");let b = a.clone();println!("{a} {b}"); // both workRemember
- E0382 means "you used a value after it moved".
- If you need the value again, clone it or (next unit) borrow it.