When should you clone?
Short answer: clone when the value has to exist in two places at once — a Vec that stores it,
or a function you don’t own that takes it by value — and when the copy is small enough that its cost
never matters. Everywhere else, borrow first: a & gives the reader what it needs without a second
buffer.
The value has to exist twice
Section titled “The value has to exist twice”A Vec<String> owns its elements. There’s no borrow that lives as long as the vector does, so
storing a value you still need means giving the vector a copy of its own:
fn main() { let name = String::from("Ada"); let mut team = Vec::new();
team.push(name.clone()); team.push(String::from("Grace"));
println!("team: {team:?}"); println!("name is still in hand: {name}");}team: ["Ada", "Grace"]name is still in hand: AdaPush name without the clone and the move ends the binding — the vector takes the only copy. The
clone is doing real work here: two owners, two buffers, each freed when its own owner goes out of
scope. A destructor shows the second buffer. The Gift type from the
previous page drops once per owner:
#[derive(Clone)]struct Gift(String);
impl Drop for Gift { fn drop(&mut self) { println!("dropping \"{}\"", self.0); }}
fn main() { let first = Gift(String::from("teddy bear")); let second = first.clone();
println!("first: {}", first.0); println!("second: {}", second.0);}first: teddy bearsecond: teddy beardropping "teddy bear"dropping "teddy bear"Two dropping lines: one per copy, so the text really was duplicated rather than shared. A single
buffer would print the line once.
The copy is too small to matter
Section titled “The copy is too small to matter”Not every clone is a performance decision. Six bytes of text cost one allocation and one six-byte memcpy:
fn main() { let label = String::from("v1.2.3"); let printed = label.clone();
println!("length: {} bytes", label.len()); println!("capacity: {} bytes", label.capacity()); println!("label: {label}"); println!("printed: {printed}"); println!("same buffer: {}", label.as_ptr() == printed.as_ptr());}length: 6 bytescapacity: 6 byteslabel: v1.2.3printed: v1.2.3same buffer: falseThe pointers differ, so the clone copied the text instead of sharing it. At this size the allocation
is noise next to the println! calls around it, and the borrow that avoids it would need a lifetime
threaded through code that runs once at startup. Clone it and move on; if a profile ever disagrees,
the fix is one line.
The boundary isn’t yours
Section titled “The boundary isn’t yours”A crate’s function takes String by value and isn’t yours to change. If you still need your copy
after the call, the clone at the call site is the price of that boundary:
fn log_and_take(message: String) { println!("log: {message}");}
fn main() { let message = String::from("disk almost full");
log_and_take(message.clone()); println!("still have: {message}");}log: disk almost fullstill have: disk almost fullFor a function you do own, changing the parameter to &str beats cloning at every call —
How to pass ownership of a value to a function
covers that move.
When clone is the wrong answer
Section titled “When clone is the wrong answer”Cloning to silence an error you haven’t read is the wrong reason, and in a hot loop it’s a real cost:
every iteration allocates. The note: under an E0382 error suggests a borrow first and a clone
second, in that order, and the
E0382 page lists the fixes. When the value needs
many readers rather than two copies, shared ownership is the shape — Rc and Arc belong to the
smart pointers chapter.
Related
Section titled “Related”- How to return ownership from a function — handing a value back instead of cloning it
- Why does my String not implement Copy? — why the free copy isn’t available
- How to tell whether a type will move or copy — which types copy without asking
- How to fix error E0382: borrow of moved value — the error clone silences
- Moves and ownership — the rest of this chapter
- Next in this chapter: how to pass a Vec to a function without cloning it