Nugget 3
Home
You pass a value to a function and suddenly you can't use it anymore.
Meet Copy and Clone — the traits that control
ownership transfer.
In Rust, assigning or passing a value moves it. The old owner can't use it anymore:
fn takes_ownership(s: String) {
println!("Got: {}", s);
}
fn main() {
let name = String::from("Rex");
takes_ownership(name);
println!("{}", name); // ❌ borrow of moved value
}
Rust does this to prevent double-free bugs — only one owner exists at a time. But sometimes you want to keep using the original.
Clone: Explicit Duplication
Call .clone() to make an explicit copy. The original stays usable:
fn takes_ownership(s: String) {
println!("Got: {}", s);
}
fn main() {
let name = String::from("Rex");
takes_ownership(name.clone()); // ✅ pass a copy, keep the original
println!("{}", name); // ✅ still alive!
}
💡 Clone is explicit by design
The .clone() call makes the performance cost visible in the
source code. You'll never accidentally copy a huge Vec or
String.
Clone
To make your own types cloneable, add #[derive(Clone)]:
#[derive(Clone)]
struct Pet {
name: String,
age: u8,
}
fn main() {
let dog = Pet { name: "Rex".into(), age: 3 };
let backup = dog.clone(); // ✅ deep copy
println!("{}", dog.name); // ✅ still accessible
}
Every field must itself implement Clone — Rust checks this when
you derive it.
Copy: Automatic Copy
Copy is Clone's simpler sibling — types that are
simple bitwise copies (like numbers and bools) can be marked Copy.
Then they copy automatically when moved:
fn takes_number(n: i32) {
println!("Got: {}", n);
}
fn main() {
let x = 42;
takes_number(x); // ✅ x is i32 — it's Copy, so it gets duplicated
println!("{}", x); // ✅ still works, no .clone() needed
}
That's why integers, booleans, and chars "just work" after being passed around —
they implement Copy.
Copy
You can derive Copy too — but only if every field is also
Copy, and you must also derive Clone:
#[derive(Debug, Clone, Copy)] // Copy requires Clone
struct Point { x: i32, y: i32 }
fn midpoint(a: Point, b: Point) -> Point {
Point {
x: (a.x + b.x) / 2,
y: (a.y + b.y) / 2,
}
}
fn main() {
let p1 = Point { x: 0, y: 0 };
let p2 = Point { x: 10, y: 20 };
let mid = midpoint(p1, p2); // both passed by copy
println!("{:?} {:?}", p1, p2); // ✅ still alive!
}
⚠️ Not everything can be Copy
Types that own heap-allocated data — String, Vec,
Box — can't be Copy. A bitwise copy of a
String would produce two pointers to the same heap memory,
causing a double-free. Use .clone() instead.
| Trait | How it copies | Code visible? | Usage |
|---|---|---|---|
Clone |
Deep copy (heap-aware) | Yes — call .clone() |
Any type |
Copy |
Bitwise memcpy | No — happens automatically | Simple types only |
| Move (default) | Transfer ownership | No — silent transfer | Any type without Copy |
#[derive(Clone)] lets you call .clone() for explicit deep copies.#[derive(Copy, Clone)] makes small types copy automatically on assignment.String, Vec) can't be Copy — only Clone.Clone before it can implement Copy.