Course contentsShow
← Rust
Lesson 189 of 1,9103. Borrowing and ReferencesFree lesson

Moving Semantics versus Copying

Distinguish between data that is moved into new bindings versus data that is bitwise copied.

In this lesson, you will learn how to distinguish between data that is moved into a new binding and data that is automatically copied by bitwise duplication.

Understanding the Two Behaviors

In Rust, when you assign a variable to another (like let y = x;), the compiler must decide how to handle the underlying data. It chooses between two paths: Moving or Copying.

The Move (The Default)

By default, Rust treats assignments as a move. When you move a variable, the ownership of the data is transferred to the new owner. The original variable becomes uninitialized and can no longer be used. This prevents double-free errors because only one variable "owns" the data at a time. This is standard for types that own heap memory, like String or Vec.

let s1 = String::from("Hello");
let s2 = s1; // The ownership is MOVED to s2.
// println!("{}", s1); // This would cause a compile error! s1 is now invalid.

The Copy (The Exception)

Some types are stored entirely on the stack and have a fixed, simple size. These types implement the Copy trait. When you assign these, Rust performs a bitwise copy—it literally copies the bits from the source to the destination. Because the original data is just a collection of bits that doesn't own any heap memory, both the old and new variables remain perfectly valid and usable.

Common Copy types include integers, floating-point numbers, and booleans.

let x = 5;
let y = x; // The bits of 5 are COPIED into y.
println!("x is {}, y is {}", x, y); // Both are valid!

How to Tell the Difference

You can think of it like this: if the data is "heavy" (like a string that might grow) or holds a pointer to the heap, Rust moves it to ensure safety. If the data is "light" (like a simple number) and the compiler knows exactly how much space it takes, Rust copies it to make your life easier. You cannot implement Copy for types that own heap resources, as the compiler enforces ownership to keep your memory safe.

Key Takeaway: Moving transfers ownership and invalidates the source, while Copying creates a duplicate and leaves the source valid—a choice Rust makes based on whether the type manages heap resources.