Rustlers Atom 2.2: `Copy` and `Clone` traits
April 18, 2026•501 words
A type that implements Copy behaves much like the old-school C integers: when you write let b = a;, the value is copied rather than moved; passing it to a function copies it; returning it from a function copies it as well; and in all these cases, the original value is still valid and can continue to be used. All the primitive scalar types you met in chapter 1 are Copy: this includes integers like i32, u64, and usize, floating-point numbers like f32 and f64, as well as bool and char. Raw pointers are also Copy, and, importantly for everyday Rust code, so are references: any &T is a Copy type.
#[derive(Copy, Clone, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p1 = Point { x: 3, y: 4 };
let p2 = p1; // copy
println!("p1 = {:?}, p2 = {:?}", p1, p2);
}
You rarely implement Copy by hand; instead, you derive it for small, plain data structs. Two important rules for Copy:
No custom destructor: A type that implements Drop (cleanup logic) cannot be Copy.
All fields must be Copy: If a struct has a String inside, it can’t be Copy.
That’s why String and Vec<T> are not Copy: they manage heap memory; if you copied them implicitly, you’d easily build double-frees or subtle bugs. If in doubt, Rust tends to say “not Copy”. You can always add .clone() where it’s really needed.
Clone: explicit duplication
Clone is a trait with one method. It is explicit and potentially expensive. You decide when to pay for a duplicate. Most standard library types implement Clone.
fn main() {
let s1 = String::from("Hello");
let s2 = s1.clone(); // new, independent String
println!("{s1} / {s2}");
let v1 = vec![1, 2, 3];
let v2 = v1.clone(); // copy the whole vector
println!("{:?} / {:?}", v1, v2);
}
Again, you usually don’t implement Clone by hand; you derive it. The derive just stitches together clone() calls for each field.
#[derive(Clone, Debug)]
struct Config {
retries: u8,
name: String,
}
fn main() {
let base = Config {
retries: 3,
name: String::from("service-A"),
};
let mut tuned = base.clone();
tuned.retries = 5;
println!("base = {:?}", base);
println!("tuned = {:?}", tuned);
}
Copy vs Clone in practice
fn main() {
// Copy type
let a = 10;
let b = a; // implicit copy
println!("{a}, {b}"); // both valid
// Clone-only type
let s1 = String::from("hi");
// let s2 = s1; // move, s1 invalid
let s2 = s1.clone(); // explicit clone
println!("{s1}, {s2}");
// Custom Copy + Clone type
#[derive(Copy, Clone)]
struct Pair { x: i32, y: i32 }
let p1 = Pair { x: 1, y: 2 };
let p2 = p1; // copy
let p3 = p1.clone(); // also fine, but redundant
println!("{} {} {}", p1.x, p2.x, p3.x);
}