Course contentsShow
← Rust
Lesson 86 of 1,9102. The Ownership ModelFree lesson

Copy Semantics for Simple Types

Identify why scalar types behave differently during assignment compared to heap-allocated types.

In this lesson, you will learn why some data types in Rust can be "copied" during assignment while others are "moved."

The "Move" by Default

So far, you’ve learned that when you assign a variable to another, ownership is typically transferred. For example, if you have a String (which lives on the heap), the pointer, length, and capacity are moved, and the original variable becomes invalid. This is because Rust wants to prevent "double-free" errors—you don't want two variables trying to clean up the same heap memory when they go out of scope.

The Exception: Scalar Types

However, not all data lives on the heap. Simple types, like integers (i32), floating-point numbers (f64), and booleans, have a fixed, known size that fits entirely on the stack. Because these types are so small and cheap to duplicate, Rust implements a trait called Copy.

When a type implements Copy, the assignment doesn't move the data. Instead, it creates a bit-for-bit duplicate. Both the original variable and the new variable remain fully valid and usable.

let x = 5;
let y = x; // Because i32 is a scalar type, it is copied, not moved.

println!("x is {}, y is {}", x, y); // Both are valid!

Why the Difference Matters

The distinction comes down to performance and safety.

  • Heap-allocated types (like String or Vec) involve a pointer to a potentially large block of memory. Moving them is cheap (just copying a few numbers), but copying the actual data would be expensive. Rust forces a "move" to ensure you only ever have one owner responsible for that heap memory.
  • Scalar types are essentially just raw numbers. Copying them is as fast as a move, and there is no "resource" (like a heap allocation) tied to them that needs to be cleaned up. Therefore, Rust allows these types to be implicitly copied, making your code much easier to write when working with simple math or flags.

Key Takeaway: Types with a known, fixed size that live entirely on the stack implement Copy, allowing them to be duplicated during assignment without invalidating the original variable.