8.5 Deriving Clone and Copy
Right, so you want to make your own types play nice with Rust’s value-copying semantics. You’ve got two traits for this: Clone and Copy. The difference is crucial, and misunderstanding it is a rite of passage. Copy is a shallow bit-for-bit duplication, and it’s automatic. The compiler just does it for you whenever a value would otherwise be moved. Clone is your explicit, user-defined deep copy operation. You have to call .clone() yourself. It’s the difference between the compiler photocopying a sheet of paper for you (Copy) and you deciding to meticulously rebuild your entire Lego Millennium Falcon, brick by identical brick (Clone).
Here’s the kicker: Copy is a marker trait. It has no methods. Its entire job is to tell the compiler, “Hey, back off, this type doesn’t need your move semantics. Just duplicate the bits.” Because it’s just a marker, you can’t implement it yourself. You can only derive it. Clone, on the other hand, has a method (fn clone(&self) -> Self) that you can implement manually if you need to do something fancy.
To Derive or Not to Derive
For about 95% of the types you’ll create, you can and should just slap #[derive(Clone, Copy)] on them and call it a day. The derive macro is brilliantly pragmatic. It does exactly what you’d expect: it generates a Clone implementation that calls clone() on each field of your struct or enum variant, and if all fields are Copy, it lets you derive Copy too.
// This is the happy path. All fields are Copy, so we can derive both.
#[derive(Clone, Copy)]
struct Point {
x: f64,
y: f64,
}
let p1 = Point { x: 3.14, y: 2.71 };
let p2 = p1; // This is a Copy! p1 is still perfectly valid.
let p3 = p1.clone(); // This is a Clone! Also fine.
The moment your type contains a non-Copy type, like a String or a Vec, the compiler will rightly refuse to derive Copy for you. You can’t have automatic bitwise copying if one of those bits is a pointer to a heap allocation—you’d just create two owners for the same data, which is a cardinal sin in Rust. You can, however, still derive Clone.
#[derive(Clone)] // Okay: derives Clone by calling clone on each field.
#[derive(Copy)] // ERROR: the trait `Copy` may not be implemented for this type
struct Person {
name: String, // String is most definitely NOT Copy.
age: u8,
}
The Clone Derive’s One Quirk (It’s a Good One)
Pay very close attention here, because this is a common “aha!” moment. The derived Clone implementation for a struct is equivalent to manually writing this:
struct Person {
name: String,
age: u8,
}
// This is what #[derive(Clone)] generates:
impl Clone for Person {
fn clone(&self) -> Self {
Self {
name: self.name.clone(), // Calls String's Clone
age: self.age.clone(), // Calls u8's Clone (which is just a Copy)
}
}
}
Notice what it does? It calls clone() on every field. This is perfect. It means if you have a field that is a Box<dyn SomeTrait>, the derived clone will call Box’s clone, which, by the magic of trait objects, will call the underlying concrete type’s clone method. This is how you get deep cloning for free. The derive macro is recursively ensuring every part of your data structure gets properly cloned. It’s one of those things that works so well you almost don’t think about it—until you need to.
When Deriving Isn’t Enough
You can’t always derive. Sometimes your type needs special cloning logic. The classic example is a type that contains a reference, like a &str or a &[u8]. The derive macro will happily generate a Clone impl for you, but it will just copy the reference, not the data it points to. This is shallow cloning, and it’s often not what you want. If your struct borrows data, the derived clone is probably correct. If your struct owns data presented as a reference (a very rare and advanced pattern), you’ll need to implement Clone manually to allocate new storage.
// A struct that borrows data. Deriving Clone is fine here.
#[derive(Clone)]
struct Tokenizer<'a> {
source: &'a str,
position: usize,
}
// Cloning this just duplicates the reference and the index. It's cheap and correct.
// A bizarre, hand-rolled arena-like struct. You must implement Clone manually.
struct MyWeirdString {
data: *const u8,
length: usize,
}
// SAFETY: This is a nightmare and requires careful consideration of
// the lifetime of the pointed-to data. The derived impl would be dangerously wrong.
impl Clone for MyWeirdString {
fn clone(&self) -> Self {
// You would need to allocate a new byte array, copy the old data into it,
// and point `data` to that new allocation. This is why we don't do this often.
unimplemented!()
}
}
The rule of thumb is simple: use #[derive(Clone)] relentlessly. It’s correct for virtually all owned data structures. Only reach for a manual implementation when you’re doing something truly exotic with raw pointers or unsafe code, or when you need to customize the cloning behavior (e.g., perhaps you want to clone most of a struct but reset a specific logfile handle to a default state). For Copy, just remember it’s an all-or-nothing proposition: either every single field is Copy, or the whole type can’t be. There’s no middle ground.