Rust ownership

Key concepts to understand first:

What Ownership addresses

  • Which parts of code are on the heap
  • Minimizing duplicate data on the heap
  • Cleaning up unused data on the heap

Ownership rules

  • Each value has a variable called its owner.
  • Only can have 1 owner at a time
  • When owner out of scope, value dropped.

Example of ownership

  • The string type, String

What the borrow checker does

Given the following error

let s1 = String::from("hello");
let s2 = s1;

println!("{}, world!", s1);

You will get this error

$ cargo run
   Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0382]: borrow of moved value: `s1`
 --> src/
2 |     let s1 = String::from("hello");
  |         -- move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
3 |     let s2 = s1;
  |              -- value moved here
4 | 
5 |     println!("{}, world!", s1);
  |                            ^^ value borrowed 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.

Reason being s1 is considered invalid after it’s value is moved to s2. Hence, no memory has to be freed when s1 moves out of scope.

If we were to keep s1 valid along with s2, it leads to a double-free error, because both s1 and s2 attempt to free them same location on the heap of memory.

If s1 frees the memory first, there is a dangling reference from s2 to the memory and vice-versa.

What if we really want to duplicate the data?

Implement and use the Clone trait.

Stack-only Data: Copy

When variables are bound to these, they can still be reused as the values implement the Copy trait.

Types have a known size at compile time have Copy:

  • All the integer types, such as u32.
  • The Boolean type, bool, with values true and false.
  • All the floating point types, such as f64.
  • The character type, char.
  • Tuples, if they only contain types that are also Copy. For example, (i32, i32) is Copy, but (i32, String) is not.