Clone Trait
Understand how Rust's Clone trait enables explicit, deep copying of values - when to derive it, how to implement it manually, and the key differences from Copy.
Rust’s ownership model ensures every value has exactly one owner at a time. When you assign a value to a new variable or pass it to a function, the original owner usually gives up ownership — the value moves. That is safe and efficient, but sometimes you genuinely need two independent copies of the same data. The Clone trait is the explicit mechanism for making that second, fully independent copy.
What the Clone Trait Is
Clone is a standard library trait that allows a type to produce a duplicate of itself through the method clone. Unlike a simple move or a bitwise copy, clone performs a deep copy — it replicates not just the top-level value but also any resources it owns, such as heap-allocated buffers. Calling .clone() is always an explicit act; the compiler never inserts clone calls on its own.
The trait itself lives in std::clone and is defined as:
pub trait Clone: Sized {
fn clone(&self) -> Self;
fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
}
Clone is a subtrait of Sized, so it can only be implemented for types whose size is known at compile time. The required method is clone, which takes an immutable reference to self and returns an owned, independent value of the same type. The provided method clone_from is a performance hook: instead of discarding an existing value and allocating a new one, it reuses the destination’s resources to overwrite it with a copy of the source.
Why Clone Exists
Without Clone, duplicating a heap-allocated value like a String would be impossible after the original owner moves. The only workaround would be to manually allocate a new buffer, copy all bytes, and reconstruct the structure — exactly the kind of repetitive, error-prone boilerplate Rust eliminates. Clone gives every type the vocabulary to express “I can duplicate myself, and here is how,” in a way callers can rely on.
The trait also serves as a gate. Not all types should be copied. A mutex guard, a file handle, a network socket — duplicating these would break invariants or create resource-management hazards. By requiring implementors to opt in and providing a method to customize the duplication, Rust prevents accidental deep copies of types that shouldn’t be cloned.
How Beginners Should Think About Clone
A useful mental model: .clone() is like ordering a photocopy of a document. You ask for it explicitly, it takes time and paper, but after you get it you have two fully separate pieces that can be modified independently without affecting each other. Rust won’t make a photocopy unless you ask, and some things (like the office’s sole master key) cannot be photocopied at all.
Deriving Clone
For most types, a straightforward field-by-field clone is exactly what you need. If every field in a struct already implements Clone, you can derive it automatically:
#[derive(Clone)]
struct Point {
x: f64,
y: f64,
}
#[derive(Clone)]
struct Drawing {
title: String,
points: Vec<Point>,
}
With #[derive(Clone)], the compiler generates a clone implementation that calls .clone() on each field. In the Drawing example, cloning produces a new String and a new Vec<Point> where every Point is also a brand-new value. The derived implementation works for enums too, cloning whichever variant is active.
Derive Works When All Fields Are Clone:
If your struct compiles with #[derive(Clone)], you can be confident every field’s clone is being called correctly. The output will be a fully independent, deep copy.
The derived code is equivalent to writing:
impl Clone for Point {
fn clone(&self) -> Self {
Point {
x: self.x.clone(),
y: self.y.clone(),
}
}
}
Primitives like f64 implement Clone by copying the raw bits, so the derived version works without extra effort. Types like String and Vec<T> have heap-backed Clone implementations that allocate new storage and copy all data across.
Manual Implementation
Deriving is sufficient for many structs, but some situations demand a custom implementation. A common case is a struct holding a raw pointer or a custom resource that requires special treatment during duplication. Another case: cloning a type where not every field itself implements Clone — for example, a reference-counted pointer behind a wrapper that you want to manage differently.
Suppose you have a simple buffer type that manually allocates memory through Vec but exposes a length field you want to keep synchronized:
struct Buffer {
data: Vec<u8>,
// We keep this field up-to-date with data.len() for fast lookups.
cached_len: usize,
}
impl Clone for Buffer {
fn clone(&self) -> Self {
// The cloned Vec already knows its length. We can avoid recomputing it
// by reading the cached length from the source. This is safe because
// the two buffers are independent after cloning.
let new_data = self.data.clone();
Buffer {
data: new_data,
cached_len: self.cached_len,
}
}
}
Here, both data and cached_len are effectively duplicated. We didn’t need to recompute the length; the cloned Vec already allocates fresh memory. The manual implementation simply copies the cached value from the source — a tiny optimization that a derived Clone would do anyway, but it shows the pattern. More importantly, if data were a raw pointer instead of a Vec, the manual implementation would need to allocate new memory and copy bytes manually — a case where deriving would be impossible.
Cloning Must Be Infallible:
The clone method cannot fail. It must either succeed or panic. If you need to handle allocation failures gracefully, you must design your API differently — for instance, using a constructor that returns Option<Self> and implementing Clone only after the allocation is known to succeed.
A struct with a field that doesn’t implement Clone cannot derive it. But you can still implement Clone manually by finding another way to create a duplicate of that field:
use std::sync::Arc;
struct SharedConfig {
inner: Arc<Config>,
}
impl Clone for SharedConfig {
fn clone(&self) -> Self {
// Arc::clone increments the reference count — no deep copy of Config.
SharedConfig {
inner: Arc::clone(&self.inner),
}
}
}
This is a legitimate and common pattern: you want SharedConfig to be Clone, even though Arc<Config> is Clone anyway, but a derived implementation would just call Arc::clone — exactly what we’ve written. The point is that manual implementation gives you control over what “clone” actually means for your type.
clone_from and Performance
The default clone_from implementation is a simple assignment: *self = source.clone(). For many types that’s fine, but for types that own large heap allocations, it might allocate a brand-new buffer and then immediately drop the old one — wasteful if the old buffer could have been reused.
Types like String and Vec override clone_from to reuse existing capacity when possible. When you write:
let mut big_string = String::with_capacity(1024);
big_string.clone_from(&source);
the implementation can copy the source’s bytes into the already-allocated buffer without performing a new allocation, provided the capacity is sufficient. The default would instead discard the buffer and allocate a new one.
If you’re implementing Clone manually for a type that manages a reusable resource, consider overriding clone_from as well. The signature is already provided; you only need to write the method body.
Clone and Copy
A common source of confusion is the relationship between Clone and the Copy marker trait. Copy is a strict subset of Clone: every Copy type must also implement Clone. The reason is that Copy guarantees a value can be duplicated by simply copying bits (a shallow, fixed-size copy), while Clone promises a deep copy. If a type is Copy, then calling .clone() is defined to behave identically to that bitwise copy, and the compiler can use that fact to automatically copy values in move positions without any explicit call.
Clone does not require Copy. A String is Clone but not Copy — cloning it allocates new heap memory. u32 is both Copy and Clone, and clone is essentially a no-op.
Copy Requires Clone:
The trait bound trait Copy: Clone {} means you must implement Clone before you can implement Copy. Deriving Copy without Clone will produce a compilation error.
When you see a type that only has Clone but not Copy, it signals that duplication is possible but may be expensive, and the caller must opt in.
Common Mistakes and Misconceptions
Deriving Clone Without Cloneable Fields:
#[derive(Clone)] works only if every field implements Clone. If you have a field of type *mut u8, PhantomData, or any non-Clone type, the derive will fail. The compiler error will point to the field that lacks Clone. Either implement Clone manually or wrap the field in a type that provides its own Clone logic.
Overusing Clone to Avoid Ownership Thinking:
It’s tempting to sprinkle .clone() everywhere to make the borrow checker happy, especially when you’re learning Rust. That often masks a design that could be solved with references or restructuring ownership. Cloning a large vector in a hot loop will cause measurable slowdowns. Consider whether you truly need an owned copy or whether a shared reference would suffice.
Clone Does Not Equal Deep Copy in All Cases:
While Clone usually performs a deep copy, the implementor decides what “clone” means. An Rc<T>’s clone only increments a reference count — the inner T is shared. A struct wrapping an Rc can still implement Clone in a way that only duplicates the pointer, not the entire tree. Always check the documentation of the type you’re cloning if the cost is critical.
One mistake specific to new Rust users: assuming that moving a value and then calling .clone() on the target will bring back the original. After a move, the original binding is unusable. This works:
let s1 = String::from("hello");
let s2 = s1.clone(); // s1 is still valid
But this does not:
let s1 = String::from("hello");
let s2 = s1; // s1 moved, no longer valid
// let s3 = s1.clone(); // compile error: use of moved value
Practical Real-World Usage
You will use Clone in many everyday Rust scenarios:
- Creating owned data from a reference: methods like
to_vec()on a slice orto_string()on a&strinternally rely onClone(or a related trait) to produce an owned copy. - Duplicating configuration objects before modifying them per-request in a web server.
- Cloning data structures when you need to keep a snapshot while continuing to mutate the original.
- Working with generic code that requires
T: Cloneto allow the function to obtain an owned value from a borrowed one.
fn duplicate_last<T: Clone>(items: &[T]) -> Vec<T> {
let mut out = items.to_vec();
if let Some(last) = items.last() {
out.push(last.clone());
}
out
}
In this function, the Clone bound is necessary because we want to push an owned copy of the last element into the vector. Without Clone, we couldn’t get an owned T from the reference.
Another pattern appears in APIs that accept impl Into<SomeType> or impl Clone to make them flexible. For example, std::collections::HashMap::entry requires the key to be Clone in some methods so it can insert a copy if the entry is vacant.
Summary
Clone gives you a clear, explicit contract: “this type can produce an independent duplicate of itself, possibly at a runtime cost.” It’s a foundation that nearly every non-trivial Rust program relies on, whether through derived implementations or carefully crafted manual ones.
The single most important insight: explicit is better than implicit. Rust forces you to call .clone() — you see every place where a potentially expensive copy happens. That visibility is a design tool, not a limitation. If you find yourself cloning the same value repeatedly in a tight loop, the call sites themselves highlight an opportunity to refactor for references or shared ownership.
Next, the Copy trait explores the narrow set of types so cheap to duplicate that Rust does it implicitly — and the strict rules that keep that implicit copying safe.