Ownership and Borrowing

Ownership

Rust by example - Ownership

  • No garbage collector. Ownership instead.
  • Each value in Rust has an owner.
  • There can only be one owner at a time.
fn main() {
    // Strings have move semantics.
    let s1 = String::from("hello");
    // s1 is MOVED into s2 - this is NOT a shallow copy
    let s2 = s1;
    println!("{}, world!", s2);
    // ...but Rust has invalidated s1
    // ERROR: println!("{}, world!", s1);
}

When the owner goes out of scope, the value will be dropped.

fn main() {
    {
        let s = String::from("hello");
        println!("{}", s);
    } // The `s` variable is now out of scope - Rust calls `drop`

    // ERROR println!("{}", s);
}

Rust will never automatically create “deep” copies of your data. Use std::clone::Clone

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();
    // `clone` deeply copies the heap data of the `String`,
    // not just the stack data.
    println!("{s2}");
}

If a type implements the std::marker::Copy⮳ trait (stack-only, fixed-size values, like integers, floats, and tuples thereof), variables that use it do not move, but rather are trivially copied, making them still valid after assignment to another variable.

fn main() {
    let x = 5; // Integer
    let y = x; // No MOVE

    println!("x = {}, y = {}", x, y); // OK
}

Borrowing

Passing a variable to a function will move or copy, just as assignment does. To avoid passing a value along, borrow the value:

fn main() {
    let s1 = String::from("hello");

    let _len = calculate_length(&s1); // `&s1` passes an immutable reference to `s1`

    fn calculate_length(s: &str) -> usize {
        s.len()
    } // Here, `s` goes out of scope. Because the function does not have
    // ownership of what it refers to, `s1` is not dropped.

    println!("{s1}");
}

Mutable references


// Note the `&mut` in the function's signature.
fn change(some_string: &mut String) {
    some_string.push_str(", world");
    println!("{some_string}");
}

fn main() {
    let mut s = String::from("hello"); // note the `mut`
    change(&mut s);
}

If you have a mutable reference to a value, you can have no other simultaneous references to that value! Functions like a read/write lock.