Skip to content

Copy, Clone macros

1. Copy Trait

The Copy trait is used for types where a bitwise copy of the data can be made. When a type implements Copy, values of that type can be duplicated simply by copying their bits, and ownership does not change. This means you don’t need to explicitly clone or move values, and you can pass them around by value without concern.

Key Properties:

  • No heap allocation: The Copy trait is used for types that are small and simple, like integers, floating-point numbers, and structs containing only Copy types.
  • Automatic Copying: When a value is assigned or passed to a function, the compiler automatically copies the value instead of moving it. This is particularly useful for primitive types.
  • No explicit cloning: You don’t need to use the .clone() method to make a copy—Rust just automatically copies the value.

Example of Copy:

fn main() {
let a = 5; // `i32` implements `Copy`
let b = a; // `a` is copied into `b`
println!("a: {}, b: {}", a, b); // This works, because `a` is not moved, it's copied (no ownership transferred)
}

In this example:

  • a is a simple integer (i32), which implements the Copy trait.
  • When we assign a to b, a is copied (not moved), and both a and b can still be used independently.

Types that implement Copy:

  • Scalar types: i32, f64, char, bool, etc.
  • Tuples: If all elements of the tuple implement Copy.
  • Arrays: If all elements of the array implement Copy.

Why Copy is Useful:

  • It allows simple, efficient duplication of data without needing explicit memory management.
  • You can pass values by value to functions and return them without worrying about borrowing or ownership issues.

2. Clone Trait

The Clone trait is for types that can explicitly create a deep copy of themselves, potentially involving heap-allocated memory or more complex copying logic. Types that implement Clone provide a .clone() method, which allows you to make a new instance with the same data.

Key Properties:

  • Deep copy: Clone is generally used for more complex types that may involve heap memory or other non-trivial data structures.
  • Explicit Cloning: Unlike Copy, which happens automatically, cloning requires an explicit .clone() call.
  • Memory management: If a type has heap-allocated data (e.g., a Vec<T> or String), cloning involves allocating new memory and copying the data.

Example of Clone:

#[derive(Clone)]
struct Person {
name: String,
age: u32,
}
fn main() {
let person1 = Person {
name: String::from("Alice"),
age: 30,
};
let person2 = person1.clone(); // Explicitly cloning `person1`
println!("person1: {}, {}", person1.name, person1.age);
println!("person2: {}, {}", person2.name, person2.age);
}

In this example:

  • Person has a String, which is heap-allocated.
  • clone() creates a deep copy of person1 to person2, so the String is cloned as well, meaning that person1 and person2 are independent.

Types that implement Clone:

  • Heap-allocated types: String, Vec<T>, etc.
  • Types with complex ownership patterns: Any type can implement Clone, but typically, this is for types that need to manage deeper copying logic than a simple bitwise copy.

Difference Between Copy and Clone

FeatureCopyClone
MethodAutomatically performed without a method (implicitly)Requires calling the .clone() method
TypesUsed for simple, fixed-size types (e.g., i32, f64)Used for more complex types that require deep copying (e.g., Vec<T>, String)
Heap MemoryWorks with types that don’t require heap allocationCan handle heap-allocated data (like String)
PerformanceTypically more efficient due to bitwise copyMight be less efficient due to deep copying logic
SemanticsImplies bitwise copying (no change in ownership)Implies deep copying, potentially requiring reallocation

When to Use Each?

  • Use Copy when you have simple, small types (like integers) where copying the data is very efficient and doesn’t require any special allocation (e.g., i32, f64, char).
  • Use Clone when you need to duplicate more complex structures, particularly when they involve heap-allocated memory, and you need to create a new instance with identical data but independent ownership.

3. Example of Types with Both Copy and Clone

Types That Implement Both:

  • i32 implements Copy, but it also implements Clone since Copy is a subset of Clone. This means you can call .clone() on an i32 as well, though it’s unnecessary.
let x = 10;
let y = x.clone(); // Works, but redundant since i32 implements `Copy`
  • Vec<T> implements Clone, but does not implement Copy, because it involves heap allocation and copying its elements in a more complex way.
let vec1 = vec![1, 2, 3];
let vec2 = vec1.clone(); // Deep copy of the vector

In the case of Vec<T>, you cannot simply assign vec1 to vec2 without cloning because Vec<T> does not implement Copy. Instead, you must call .clone().


Summary:

  • Copy: A marker trait for types where values can be duplicated by simple bitwise copying. It’s used for types like integers and other fixed-size, simple types.
  • Clone: A trait for types that need to perform a deep copy, and typically involves more complex operations like memory allocation. It’s used for types like String, Vec<T>, etc.

Copy is an automatic, efficient, shallow duplication, while Clone gives more control and works for more complex types requiring a deep copy.