Ownership and Moves

RustRustBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, it is explained that in Rust, variables have ownership of resources and can only have one owner, which prevents resources from being freed multiple times. When variables are assigned or function arguments are passed by value, the ownership of resources is transferred, known as a move. After the move, the previous owner can no longer be used to avoid creating dangling pointers. The code example demonstrates these concepts by showing how the ownership of stack-allocated and heap-allocated variables is transferred and how accessing a variable after its ownership has been moved leads to errors.

Note: If the lab does not specify a file name, you can use any file name you want. For example, you can use main.rs, compile and run it with rustc main.rs && ./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("`Rust`")) -.-> rust/BasicConceptsGroup(["`Basic Concepts`"]) rust(("`Rust`")) -.-> rust/DataTypesGroup(["`Data Types`"]) rust(("`Rust`")) -.-> rust/FunctionsandClosuresGroup(["`Functions and Closures`"]) rust(("`Rust`")) -.-> rust/MemorySafetyandManagementGroup(["`Memory Safety and Management`"]) rust(("`Rust`")) -.-> rust/DataStructuresandEnumsGroup(["`Data Structures and Enums`"]) rust(("`Rust`")) -.-> rust/AdvancedTopicsGroup(["`Advanced Topics`"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("`Variable Declarations`") rust/DataTypesGroup -.-> rust/integer_types("`Integer Types`") rust/DataTypesGroup -.-> rust/type_casting("`Type Conversion and Casting`") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("`Function Syntax`") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("`Expressions and Statements`") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("`Lifetime Specifiers`") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("`Method Syntax`") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("`Traits for Operator Overloading`") subgraph Lab Skills rust/variable_declarations -.-> lab-99195{{"`Ownership and Moves`"}} rust/integer_types -.-> lab-99195{{"`Ownership and Moves`"}} rust/type_casting -.-> lab-99195{{"`Ownership and Moves`"}} rust/function_syntax -.-> lab-99195{{"`Ownership and Moves`"}} rust/expressions_statements -.-> lab-99195{{"`Ownership and Moves`"}} rust/lifetime_specifiers -.-> lab-99195{{"`Ownership and Moves`"}} rust/method_syntax -.-> lab-99195{{"`Ownership and Moves`"}} rust/operator_overloading -.-> lab-99195{{"`Ownership and Moves`"}} end

Ownership and moves

Because variables are in charge of freeing their own resources, resources can only have one owner. This also prevents resources from being freed more than once. Note that not all variables own resources (e.g. [references]).

When doing assignments (let x = y) or passing function arguments by value (foo(x)), the ownership of the resources is transferred. In Rust-speak, this is known as a move.

After moving resources, the previous owner can no longer be used. This avoids creating dangling pointers.

// This function takes ownership of the heap allocated memory
fn destroy_box(c: Box<i32>) {
    println!("Destroying a box that contains {}", c);

    // `c` is destroyed and the memory freed
}

fn main() {
    // _Stack_ allocated integer
    let x = 5u32;

    // *Copy* `x` into `y` - no resources are moved
    let y = x;

    // Both values can be independently used
    println!("x is {}, and y is {}", x, y);

    // `a` is a pointer to a _heap_ allocated integer
    let a = Box::new(5i32);

    println!("a contains: {}", a);

    // *Move* `a` into `b`
    let b = a;
    // The pointer address of `a` is copied (not the data) into `b`.
    // Both are now pointers to the same heap allocated data, but
    // `b` now owns it.

    // Error! `a` can no longer access the data, because it no longer owns the
    // heap memory
    //println!("a contains: {}", a);
    // TODO ^ Try uncommenting this line

    // This function takes ownership of the heap allocated memory from `b`
    destroy_box(b);

    // Since the heap memory has been freed at this point, this action would
    // result in dereferencing freed memory, but it's forbidden by the compiler
    // Error! Same reason as the previous Error
    //println!("b contains: {}", b);
    // TODO ^ Try uncommenting this line
}

Summary

Congratulations! You have completed the Ownership and Moves lab. You can practice more labs in LabEx to improve your skills.

Other Rust Tutorials you may like