Skip to content

Chapter 2 of 8

Moves, Copy, and Clone

When you assign a value to another variable or pass it to a function, Rust moves the value rather than copying it by default. After a move, the source binding is invalidated, and any attempt to use it is rejected at compile time. This design avoids double-free bugs that would otherwise arise if two bindings each believed they owned the same heap allocation: copying the pointer of a String would produce two would-be droppers of the same buffer. Move semantics keep the type system simple by ensuring only one entity is ever responsible for cleanup.

Some types opt out of moving through the Copy trait, a marker trait that signifies bitwise duplication is safe and that no special cleanup is needed. Integers, bool, char, tuples whose elements are all Copy, and any other type without heap-allocated resources typically implement Copy. The compiler refuses to let a type implement both Copy and Drop, because Copy implies that nothing of importance happens at the end of the value's lifetime. Copy technically requires Clone, but the two traits have very different flavors: Copy is implicit and free, while Clone is an explicit method .clone() that may perform arbitrary and potentially expensive work to produce a deep, independent copy.

Calling clone() is the standard way to deliberately duplicate data so that two bindings each own their own copy. It should be used when an independent value is genuinely required — for example, when multiple threads each need their own data — rather than as a habitual escape hatch from the borrow checker. The Clone trait has a simple signature, fn clone(&self) -> Self, taking a shared reference and returning a freshly owned value. Arrays follow the same rules as their elements: an array of Copy integers is itself Copy and duplicates on assignment, while an array of String is not Copy and will move element-by-element when needed.

All chapters
  1. 1Ownership Rules and Memory
  2. 2Moves, Copy, and Clone
  3. 3Borrowing and the Borrow Checker
  4. 4Lifetimes, Variance, and PhantomData
  5. 5Slices, Strings, and Deref Coercion
  6. 6Interior Mutability and Runtime Enforcement
  7. 7Shared Ownership Across Threads
  8. 8Patterns, Iteration, and Unsized Types

Drill it

Reading is not remembering. These come from the Rust Ownership And Borrowing Explained deck:

Q

What are the three ownership rules in Rust?

Each value in Rust has an owner. There can only be one owner at a time. When the owner goes out of scope, the value is dropped.

Q

What happens to a value when its owner goes out of scope in Rust?

It is dropped — its drop function runs and its memory is freed.

Q

Which standard library function is called when a value goes out of scope?

drop, from the Drop trait, is called automatically at the end of the variable's scope.

Q

What is a "move" in Rust?

A transfer of ownership: assigning a value to another variable or passing it to a function moves the value, invalidating the source binding.