Question

Rust Copy vs Clone: What’s the Difference?

Question

In Rust, what is the difference between Copy and Clone?

I found a discussion that makes it sound like the difference might only be an implementation detail, such as memcpy versus something else, but I cannot find a clear, explicit explanation of how these two traits differ in meaning and usage.

Short Answer

By the end of this page, you will understand how Copy and Clone differ in Rust, why they exist as separate traits, how they interact with ownership, and when to use each one. You will also see practical examples of values that are copied automatically versus values that must be cloned explicitly.

Concept

In Rust, Copy and Clone both relate to making duplicate values, but they mean different things.

  • Copy means a value can be duplicated implicitly just by assigning it, passing it to a function, or returning it.
  • Clone means a value can be duplicated explicitly by calling .clone().

The important difference is not just performance or implementation. The real difference is about ownership semantics and safety guarantees.

Copy

A type that implements Copy is so simple and safe to duplicate that Rust allows duplication automatically. When you assign it to another variable, the original is still usable.

Examples:

  • integers like i32
  • floating-point values like f64
  • bool
  • char
  • tuples of Copy types
  • references like &T

These types do not need special cleanup logic when they go out of scope.

Clone

A type that implements Clone can also be duplicated, but Rust requires you to say so explicitly with .clone().

Examples:

  • String
  • Vec<T>
  • HashMap<K, V>

These types often own heap-allocated data. Duplicating them may require allocating new memory and copying the underlying contents.

Why separate traits?

Rust uses ownership to prevent memory errors. If every value were duplicated automatically, it would be too easy to accidentally make expensive copies or create confusing ownership behavior.

So Rust splits duplication into two levels:

  • Cheap, always-safe implicit duplication: Copy
  • Potentially more expensive or meaningful duplication: Clone

Relationship between them

In Rust, Copy types must also implement Clone.

That means:

  • every Copy type is also Clone
  • not every Clone type is Copy

This is because if a value can be copied implicitly, it must also be possible to duplicate it explicitly.

Ownership behavior

For non-Copy types, assignment usually moves ownership.

let s1 = String::from("hello");
let s2 = s1;
// s1 can no longer be used here

For Copy types, assignment copies the value.

let x = 5;
let y = x;
// x is still valid
println!("{} {}", x, y);

For Clone types, you can request a duplicate manually.

let s1 = String::from("hello");
let s2 = s1.clone();
println!("{} {}", s1, s2);

Why String is Clone but not Copy

A String contains owned heap memory. If Rust allowed it to be Copy, then simple assignment would silently duplicate heap data all the time, which could be expensive and surprising.

Instead, assignment moves the String, and .clone() makes a full duplicate when you really want one.

Why this matters in real programming

Understanding Copy vs Clone helps you:

  • predict whether a value will move or stay usable
  • avoid ownership errors
  • write APIs that are efficient and clear
  • prevent unnecessary allocations
  • understand why some values need .clone() and others do not

Mental Model

Think of Rust values as items you can hand to someone.

  • A Copy value is like handing out a photocopy of a small note. You still keep your original automatically.
  • A Clone value is like owning a physical folder full of documents. If someone else needs their own folder, you must deliberately ask for a duplicate to be made.
  • A move is like handing over the only original folder. After that, you no longer have it.

This mental model explains why Rust treats small simple values differently from heap-owning values:

  • small note → easy to duplicate automatically
  • large folder → duplicate only when you ask

So the distinction is not just how bytes are copied in memory. It is about whether Rust allows duplication to happen silently as part of normal ownership flow.

Take Quiz

Syntax and Examples

Basic syntax

Clone is used explicitly:

let a = String::from("hello");
let b = a.clone();

Copy happens implicitly on assignment:

let x = 10;
let y = x;

Example 1: Copy type

fn main() {
    let a = 42;
    let b = a;

    println!("a = {}, b = {}", a, b);
}

i32 implements Copy, so assigning a to b duplicates the value automatically. Both variables are valid.

Example 2: non-Copy type

fn main() {
    let a = String::from("hello");
    let b = a;

    // println!("{}", a); // error: value was moved
    println!("{}", b);
}

String does not implement Copy, so assignment moves ownership from a to b.

Example 3: cloning a non-Copy type

fn main() {
    let a = String::from("hello");
    let b = a.clone();

    println!("a = {}, b = {}", a, b);
}

Now both a and b are valid because .clone() creates a second owned String.

Deriving Copy and Clone

For your own simple types, you can often derive both:

#[derive(Copy, Clone, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1;

    println!("p1 = {:?}, p2 = {:?}", p1, p2);
}

This works because all fields of Point are themselves Copy.

When deriving Copy does not work

#[derive(Clone, Debug)]
struct User {
    name: String,
}

This type can be Clone, but not Copy, because String is not Copy.

Step by Step Execution

Consider this example:

fn main() {
    let s1 = String::from("rust");
    let s2 = s1.clone();
    let n1 = 7;
    let n2 = n1;

    println!("{} {}", s1, s2);
    println!("{} {}", n1, n2);
}

Here is what happens step by step:

  1. let s1 = String::from("rust");

    • A String is created.
    • s1 owns its heap-allocated text.
  2. let s2 = s1.clone();

    • Rust calls the Clone implementation for String.
    • A new heap allocation is made.
    • The contents "rust" are copied into the new allocation.
    • s1 and s2 now own separate String values.
  3. let n1 = 7;

    • n1 stores an integer.
  4. let n2 = n1;

    • Since i32 is Copy, Rust duplicates the value automatically.
    • Both n1 and n2 are valid.
  5. println!("{} {}", s1, s2);

    • Works because both strings exist independently.
  6. println!("{} {}", n1, n2);

    • Works because integers are copied, not moved.

Now compare with this version:

fn main() {
    let s1 = String::from("rust");
    let s2 = s1;

    // println!("{}", s1); // error
    println!("{}", s2);
}

Step by step:

  1. s1 owns the string.
  2. let s2 = s1; moves ownership.
  3. s1 becomes invalid.
  4. Only s2 may be used after the move.

Real World Use Cases

Where Copy is used

Copy is common for small value-like data:

  • numeric calculations
  • coordinates and dimensions
  • timestamps or counters
  • flags and options
  • lightweight IDs

Example:

#[derive(Copy, Clone)]
struct Size {
    width: u32,
    height: u32,
}

A type like Size behaves like plain data. Copying it is cheap and expected.

Where Clone is used

Clone is common for owned data structures:

  • duplicating request payloads
  • copying configuration values
  • reusing strings across tasks
  • creating independent collections for processing
  • snapshotting application state

Example:

let config_name = String::from("production");
let backup_name = config_name.clone();

In APIs and data processing

You often see:

  • Copy for simple enums and small structs
  • Clone for owned strings, vectors, maps, and smart pointers

This makes code communicate cost and intent clearly.

Take Quiz

Real Codebase Usage

In real Rust projects, developers use Copy and Clone as part of API design.

Common patterns

Small domain types are often Copy

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    Active,
    Disabled,
}

Enums like this are cheap to duplicate and easy to pass around.

Owned data is usually Clone

#[derive(Clone, Debug)]
struct AppConfig {
    app_name: String,
    port: u16,
}

The String field means the struct should not be Copy, but Clone is useful when multiple parts of the program need similar config data.

Avoid cloning unless needed

Experienced Rust developers try not to call .clone() automatically everywhere. Instead, they often:

  • borrow with &T
  • pass references into functions
  • return references when appropriate
  • move ownership deliberately when the old value is no longer needed

Cloning to satisfy ownership boundaries

Sometimes cloning is the right tool:

  • sending owned data into a thread or async task
  • storing a value in multiple places
  • keeping an original while transforming a duplicate

Derive traits for ergonomic types

It is common to write:

#[derive(Clone, Debug)]
struct User {
    username: String,
    age: u32,
}

And for plain data:

#[derive(Copy, Clone, Debug)]
struct Position {
    x: f32,
    y: f32,
}

This helps other developers immediately understand whether assignment will move or copy the type.

Common Mistakes

Mistake 1: Thinking Copy and Clone only differ in speed

They differ in meaning, not just performance.

  • Copy = implicit duplication allowed
  • Clone = explicit duplication required

Even if a clone happens to be cheap, that does not automatically make the type suitable for Copy.

Mistake 2: Expecting assignment to duplicate a String

Broken example:

let a = String::from("hello");
let b = a;
println!("{}", a); // error

Why it fails:

  • String is moved, not copied.

Fix:

let a = String::from("hello");
let b = a.clone();
println!("{} {}", a, b);

Mistake 3: Deriving Copy for a type with non-Copy fields

Broken example:

#[derive(Copy, Clone)]
struct Person {
    name: String,
}

Why it fails:

  • all fields must be Copy for the whole type to be Copy

Fix:

#[derive(Clone)]
struct Person {
    name: String,
}

Mistake 4: Using .clone() when borrowing is enough

Unnecessary clone:

fn print_name(name: String) {
    println!("{}", name);
}

let name = String::from("Ada");
print_name(name.clone());
println!("{}", name);

Better:

fn print_name(name: &str) {
    println!("{}", name);
}

let name = String::from("Ada");
print_name(&name);
println!("{}", name);

Borrowing is often cleaner and more efficient.

Mistake 5: Assuming Copy can be implemented for any type

Types with destructors or owned resources generally cannot be Copy.

For example, String manages heap memory and has cleanup behavior when dropped. That is one reason it is not Copy.

Comparisons

ConceptCopyClone
How duplication happensImplicitlyExplicitly with .clone()
Assignment behaviorDuplicates valueUsually moves unless cloned
Typical costCheapMay be cheap or expensive
Requires programmer intentNoYes
Good for heap-owning dataNoYes
Must also implement CloneYesNot necessarily Copy

Copy vs move

BehaviorCopy typesNon-Copy types
let b = a;a is still usablea is moved and becomes unusable
Passing to functionvalue is copiedownership is moved unless borrowed
Return from functioncopied if neededmoved

Clone vs borrowing

ApproachWhat it doesWhen to use it
.clone()Makes a new owned valueWhen you need two independent owners
&T or &strTemporarily borrowsWhen you only need to read or use data

In practice, if you do not need ownership of a second independent value, borrowing is often better than cloning.

Take Quiz

Cheat Sheet

Quick rules

  • Copy = implicit duplication
  • Clone = explicit duplication with .clone()
  • All Copy types must also be Clone
  • Not all Clone types are Copy
  • Assignment of non-Copy values usually moves ownership

Common Copy types

i32, u64, f32, bool, char, &T

Common Clone but not Copy types

String, Vec<T>, HashMap<K, V>

Basic examples

let x = 1;
let y = x; // copied
let s1 = String::from("hi");
let s2 = s1; // moved
let s1 = String::from("hi");
let s2 = s1.clone(); // cloned

Deriving traits

#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

Only works if all fields are Copy.

Good habit

  • Prefer borrowing when you do not need a separate owned value
  • Use .clone() only when you truly need duplication
  • Use Copy for small plain-data types

FAQ

Is Copy just a faster version of Clone?

No. The main difference is semantic: Copy happens implicitly, while Clone must be called explicitly. Performance is not the whole story.

Why does String implement Clone but not Copy?

Because String owns heap memory. Automatic copying on every assignment would be expensive and surprising, so Rust requires explicit cloning.

Can I implement Copy without Clone?

No. In Rust, a type that is Copy must also be Clone.

How do I know whether assignment moves or copies?

Check whether the type implements Copy. If it does, assignment copies. If it does not, assignment usually moves.

Should I call .clone() to fix ownership errors?

Sometimes, but not always. Many ownership errors are better solved by borrowing with references instead of cloning.

Can structs be Copy?

Yes, if all their fields are Copy and the type does not require special cleanup.

Are references Copy?

Yes, shared references like &T are Copy. Copying a reference copies the pointer-like value, not the underlying data.

Take Quiz

Mini Project

Description

Build a small Rust program that demonstrates the difference between moving, copying, and cloning values. This project is useful because it turns an abstract ownership rule into behavior you can observe directly in code.

Goal

Create a program that shows one Copy type being reused after assignment and one Clone-only type being duplicated explicitly.

Requirements

  1. Create one custom type that can derive Copy and Clone.
  2. Create one custom type that contains a String and derives only Clone.
  3. Show that assigning the Copy type leaves the original usable.
  4. Show that cloning the Clone-only type creates two independent owned values.
  5. Print results that make the difference visible.
Take Quiz

Keep learning

Related questions

View more