← Back to Rust Course | Chapter 5: Ownership | Lesson 2 of 6

Move Semantics

When you hand a value to someone else in Rust, you can't use your old copy of it anymore -- it really moved.
Syntax
rust
let a = String::from("text");
let b = a;  // a moved into b, a is no longer valid

Moving Ownership on Assignment

When you assign a String (or other heap-allocated, non-Copy type) to a new variable, Rust moves the underlying data's ownership rather than copying it, and invalidates the original variable.

Example: Moving Ownership on Assignment

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `original`, set to `String::from("Rustacean")`
    let original = String::from("Rustacean");
    // Declare an immutable variable `moved`, set to `original`
    let moved = original;
    // Print "moved holds: {}" to the console, substituting in `moved` (with a trailing newline)
    println!("moved holds: {}", moved);
}

Moves Happen on Function Calls Too

Passing a non-Copy value into a function moves ownership into that function's parameter. After the call, the caller's variable is no longer valid unless the value is returned back.

Example: Moves Happen on Function Calls Too

markup
// Define the function `take_ownership` taking `s`
fn take_ownership(s: String) {
    // Print "Function now owns: {}" to the console, substituting in `s` (with a trailing newline)
    println!("Function now owns: {}", s);
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `text`, set to `String::from("hello")`
    let text = String::from("hello");
    take_ownership(text);
    // Print "text was moved into the function" to the console (with a trailing newline)
    println!("text was moved into the function");
}

Getting a Value Back by Returning It

A function can return ownership of a value back to the caller, letting you keep using it under a (possibly new) variable name after the call.

Example: Getting a Value Back by Returning It

markup
// Define the function `process` taking `s` and returning a String
fn process(s: String) -> String {
    // Print "Processing: {}" to the console, substituting in `s` (with a trailing newline)
    println!("Processing: {}", s);
    s
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `text`, set to `String::from("data")`
    let text = String::from("data");
    // Declare an immutable variable `text`, set to `process(text)`
    let text = process(text);
    // Print "Back in main: {}" to the console, substituting in `text` (with a trailing newline)
    println!("Back in main: {}", text);
}

Why Rust Uses Moves Instead of Deep Copies

Copying large heap-allocated data every time it is assigned would be slow. Moves let Rust transfer ownership cheaply (just copying a pointer, length, and capacity) while the compiler guarantees only one owner uses that memory.

Example: Why Rust Uses Moves Instead of Deep Copies

markup
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `large_data`, set to `vec![1; 5]`
    let large_data = vec![1; 5];
    // Declare an immutable variable `transferred`, set to `large_data`
    let transferred = large_data;
    // Print "Transferred without deep copy: {:?}" to the console, substituting in `transferred` (with a trailing newline)
    println!("Transferred without deep copy: {:?}", transferred);
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Trying to use a variable after moving its value into another variable or into a function, causing a compile error.
  2. Assuming assignment always copies data like it might in some other languages -- for heap types, assignment moves by default.
  3. Confusing a move with a shallow copy that leaves two usable references to the same data -- Rust invalidates the original.
Chapter Summary
  • Assigning a non-Copy value to another variable moves ownership; the original variable becomes invalid.
  • Passing a non-Copy value into a function also moves it, unless the function takes a reference.
  • Using a moved-from variable is a compile-time error, not a runtime bug.
  • Move semantics avoid the cost of deep-copying data while still preventing use-after-free.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.