Copy vs Clone in Rust
The difference between Copy and Clone in Rust: implicit bitwise copies vs explicit .clone(), which types are Copy, and when to derive each.
Both Copy and Clone produce a duplicate of a value, but they work very differently.
Copy |
Clone |
|
|---|---|---|
| How it happens | implicitly, on every assignment or call | explicitly, when you write .clone() |
| What it does | copies the bits on the stack | whatever the type's clone method does (often a deep copy) |
| Cost | always cheap | can be expensive (allocates, copies heap data) |
| Old value afterwards | still usable | still usable |
| Examples | i32, f64, bool, char, &T, (i32, i32), [u8; 4] |
String, Vec<T>, HashMap, Box<T>, plus every Copy type |
Copy: values that are just bits
A type can be Copy only if duplicating its bytes produces a correct, independent value. An i32 qualifies: two copies of the number 5 never interfere. A String doesn't: its bytes are a pointer to heap memory, so a bitwise copy would give two owners of the same text, and a double free when both are dropped. That's why String moves instead.
Shared references &T are Copy (many readers are allowed), but &mut T is not (only one writer at a time).
Clone: an explicit, possibly expensive duplicate
.clone() asks a type to make a full, independent copy. For a String it allocates new heap memory and copies the text. Because it's explicit, you can see every place your code pays for a copy.
Deriving them for your own types
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
x: i32,
y: i32,
}
Copy requires Clone (it's a supertrait), so you always derive both. You can only derive Copy if every field is Copy:
#[derive(Clone, Copy)]
struct Player {
name: String,
score: u32,
}
fn main() {}
error[E0204]: the trait `Copy` cannot be implemented for this type
--> src/main.rs:2:8
|
1 | #[derive(Clone, Copy)]
| ---- in this derive macro expansion
2 | struct Player {
| ^^^^^^
3 | name: String,
| ------------ this field does not implement `Copy`
Derive only Clone for such types. A type that implements Drop can't be Copy either.
When to derive Copy
Derive Copy for small value types: coordinates, colors, ids, money amounts, small enums like Direction. Code using them reads naturally (let p2 = p1;) and there's no performance cost.
Think twice before making a type Copy if it might later gain a String or Vec field: removing Copy then is a breaking change for every user of the type. For large structs, Copy can also hide expensive memcpys.
Common mistakes
- Cloning to silence the borrow checker. It compiles, but each clone of a
Vec<String>copies every string. First ask whether a reference (&) would do. - Calling
.clone()on aCopyvalue. It works but is noise; clippy saysclone_on_copy("usingcloneon typePointwhich implements theCopytrait"). - Expecting a clone to stay in sync. A clone is independent: changing it doesn't change the original. For shared data, use a reference or
Rc/Arc. Rc::cloneis cheap. Cloning anRcorArccopies a pointer and bumps a counter; it does not copy the data. WritingRc::clone(&x)instead ofx.clone()makes that obvious to readers.
Example
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
x: i32,
y: i32,
}
#[derive(Debug, Clone)]
struct Player {
name: String,
pos: Point,
}
fn main() {
let a = Point { x: 1, y: 2 };
let mut b = a; // Copy: a is still usable
b.x = 10;
println!("{a:?} {b:?}");
let p1 = Player { name: String::from("Ferris"), pos: a };
let mut p2 = p1.clone(); // Clone: the String's text is copied too
p2.name.push_str(" II");
p2.pos.y += 5;
println!("{} at {:?}", p1.name, p1.pos);
println!("{} at {:?}", p2.name, p2.pos);
println!("same position: {}", p1.pos == p2.pos);
let nums = vec![1, 2, 3];
let total: i32 = nums.iter().copied().sum(); // copied(): &i32 -> i32
println!("{nums:?} total {total}");
}
Output:
Point { x: 1, y: 2 } Point { x: 10, y: 2 }
Ferris at Point { x: 1, y: 2 }
Ferris II at Point { x: 1, y: 7 }
same position: false
[1, 2, 3] total 6