Ownership

Ownership is one of the three central pillars in Rust's memory model, where the others are Borrowing and Lifetimes. Ownership can be summarized in the following three rules:

  • Each value in Rust has a variable that’s called its owner.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value will be dropped.

When a value is transferred from one owner to another, this called a move. After the move, the previous owner can no longer access the value.

ExampleEdit

fn foo(a: String, b: String) -> String {
    // Here, the strings are owned by by the variables `a` and `b`.

    // This moves `a` into `c`, so `c` becomes the new owner of the string.
    // After this, `a` can no longer be used.
    let c = a;

    // Gives ownership of `b` to the `drop` function.
    // After this, `b` can no longer be used.
    drop(b);

    // `clone()` makes a deep copy. `c` and `d` are now identical strings.
    let d = c.clone();

    // Returns `d`, which moves the value to the calling function
    d

    // Here `c` goes out of scope, while still owning a string.
    // Therefore it is dropped and its destructors are run.
}

The Drop traitEdit

A scope is a region of code surrounded by curly braces ({}). In the example above, the function foo is a scope, and the parameters a and b as well as the local variables c and d only exist within this scope.

The ownership rules mention that values that go out of scope are dropped. Often, this means releasing a resource; for example, the String  type allocates memory and dropping it will free it. To do this, it implements the Drop  trait, which acts as a destructor. Whenever a value that implements Drop goes out of scope, this destructor is run automatically.

The Copy traitEdit

Some values, such as primitive types, are very small, so it's cheap to copy them. These types usually implement the Copy  trait. This means that they are are copied instead of being moved like all other values. Example:

let a: i32 = 5;
let b = a;
let c = a;
let d = a + b - c;
// all four variables now own a number

This would not be possible if i32 didn't implement the Copy trait, because then a would be moved into b and accessing a after this would produce a compiler error. But thanks to the Copy trait, this works as desired.

As Copy types are constantly being duplicated and destroyed, Copy is mutually exclusive with Drop. Copyable types should only ever be used to simply store some data (such as an integer or a character) rather than control an external resource (such as memory or a file).