Clone, Copy, and what's cheap
Worked examples
Read the claim, then run it and check the machine agrees. One at a time — nothing here is taken on trust.
#[derive(Debug, Clone, Copy)]
struct Point { x: i32, y: i32 }
fn manhattan(p: Point) -> i32 {
p.x.abs() + p.y.abs()
}
fn main() {
let p = Point { x: 3, y: -4 };
let d1 = manhattan(p); // p is COPIED into manhattan...
let d2 = manhattan(p); // ...so p is still ours here
println!("{p:?} -> {d1} and again {d2}");
}
Because Point derives Copy, passing p by value duplicates its
8 bytes instead of moving — so the second manhattan(p) is legal
and p is still printable at the end. Drop the Copy from the
derive and the second call becomes E0382: value used after move.
Prints Point { x: 3, y: -4 } -> 7 and again 7.
fn shout(s: String) -> String {
s.to_uppercase()
}
fn main() {
let name = String::from("ferris");
let loud = shout(name.clone()); // give shout its OWN copy
// without .clone(), name would be moved and the next line E0382:
println!("kept the original: {name}");
println!("and shouted: {loud}");
// proof they're independent allocations:
let a = String::from("hi");
let b = a.clone();
println!("different heap buffers: {}", a.as_ptr() != b.as_ptr());
}
String isn't Copy, so to keep name after passing it to shout
you clone explicitly — a new heap buffer, visible at the call site.
The final line prints true: the clone's pointer differs from the
original's, so each is freed independently. You pay one allocation
and you can see exactly where.
#[derive(Debug, Clone)] // Clone is fine; Copy would be rejected
struct Label { text: String }
fn main() {
let a = Label { text: String::from("hi") };
let b = a.clone(); // explicit deep copy: new heap buffer
// Adding Copy to the derive above fails to compile:
// error[E0204]: the trait `Copy` cannot be implemented for
// this type; field `text` does not implement `Copy`
println!("{a:?} and its clone {b:?}");
}
Label owns a String, so Clone works (deep copy, one
allocation) but Copy is forbidden — E0204 spells out why: a field
doesn't implement Copy. The compiler won't let a heap owner be
duplicated silently, because that's the double-free the move rule
exists to prevent. Prints both labels via their derived Debug.
Check the concept
One question at a time. Unsure? Revisit the lecture, then answer.
The challenge
Pass the quiz to unlock the challenge — your code will still be waiting here.