What is the difference between move, copy, and clone semantics in Rust?
Understand move, copy, and clone semantics in Rust: how ownership transfers, when values duplicate cheaply, and when to call .clone() for a deep copy.
Expected Interview Answer
A move transfers ownership of a value to a new binding and invalidates the old one; a copy makes a cheap bitwise duplicate for simple stack-only types that implement the Copy trait; and a clone performs an explicit, possibly expensive deep duplication via the Clone trait when you call .clone().
By default, assigning or passing a non-Copy value moves it, so the original can no longer be used and there is no double-free of heap data. Types made of purely stack data (like integers) implement Copy, so assignment duplicates them and both bindings stay valid. When you need an independent copy of a heap-owning type such as String or Vec, you must call .clone() explicitly, which the language keeps visible because it can be costly.
- Prevents double-free by invalidating moved-from values
- Copy makes trivial stack values ergonomic to reuse
- Clone makes expensive duplication explicit and visible
- No hidden deep copies happen behind your back
- Ownership rules stay enforced with zero runtime cost
AI Mentor Explanation
A move is handing the match ball to the next bowler — once passed, you no longer hold it and cannot bowl with it. Copy is like giving someone the agreed score, a trivial number both of you now know independently. Clone is manufacturing a brand-new identical ball from scratch: deliberate, costly, and only done when you explicitly ask for a second genuine ball.
Step-by-Step Explanation
Step 1
Assign a non-Copy value
Binding one variable to another (let b = a) moves ownership; using a afterward is a compile error.
Step 2
Assign a Copy value
For types implementing Copy (integers, bools, char, simple structs of Copy fields), assignment duplicates bitwise and both remain valid.
Step 3
Decide when you need Clone
If you need an independent copy of a heap-owning type, call .clone() explicitly to deep-copy the owned data.
Step 4
Understand the trait relationship
Copy requires Clone as a supertrait; Copy is an implicit, cheap duplication while Clone is an explicit, potentially deep one.
Step 5
Watch for moves into functions
Passing a non-Copy value to a function moves it in; borrow with & instead if you want to keep using it afterward.
What Interviewer Expects
- Knowing move invalidates the source binding
- Understanding Copy is implicit and only for stack-safe types
- Understanding Clone is explicit and possibly expensive
- Knowing Copy has Clone as a supertrait
- Explaining why moves prevent double-free of heap data
Common Mistakes
- Thinking a plain assignment of a String copies its heap data
- Believing you can use a value after it has been moved
- Assuming .clone() is always cheap
- Trying to implement Copy for a type that owns heap memory
- Confusing Clone's deep copy with a shallow reference
Best Answer (HR Friendly)
“In Rust, a move hands ownership of data to a new variable and disables the old one, a copy is a cheap automatic duplicate reserved for simple values, and a clone is an on-demand full duplicate you ask for by name. This keeps memory safe and makes expensive copies obvious in the code.”
Code Example
fn main() {
// Copy: i32 implements Copy, both stay valid
let a = 5;
let b = a;
println!("{} {}", a, b); // OK
// Move: String owns heap data, ownership transfers
let s1 = String::from("hello");
let s2 = s1;
// println!("{}", s1); // ERROR: value borrowed after move
println!("{}", s2); // OK
// Clone: explicit deep copy, both independent
let s3 = s2.clone();
println!("{} {}", s2, s3); // OK, two separate allocations
}Follow-up Questions
- Why can't a type that owns heap memory implement Copy?
- What is the relationship between the Copy and Clone traits?
- How does moving a value into a function affect the caller?
- When would you derive Clone but not Copy?
- How do move closures capture their environment?
MCQ Practice
1. After `let s2 = s1;` where s1 is a String, what happens to s1?
String is not Copy, so assignment moves ownership to s2 and using s1 afterward is a compile error.
2. Which statement about the Copy trait is correct?
Copy is a supertrait relationship over Clone; it is implicit, cheap, and only valid for types with no heap ownership.
3. How do you get an independent duplicate of a Vec<String>?
Vec owns heap data and is not Copy, so you must explicitly call .clone() to deep-copy it into an independent value.
Flash Cards
What is a move in Rust? — Ownership of a value transfers to a new binding and the original becomes invalid to use.
What is Copy semantics? — An implicit, cheap bitwise duplication for stack-only types implementing the Copy trait; both bindings stay valid.
What is Clone semantics? — An explicit, possibly expensive deep duplication performed by calling .clone() via the Clone trait.
Why can't String be Copy? — It owns heap memory, so a bitwise copy would risk a double-free; duplication must be an explicit clone.
Relationship between Copy and Clone? — Copy has Clone as a supertrait — anything Copy is also Clone, but not vice versa.