Home Rust Programming Difference between Copy and Clone traits in Rust

Difference between Copy and Clone traits in Rust

Copy trait and Clone traits are important concepts in the Rust programming language. Theoretically, they are easy but are hard to apply in real life, especially for new programmers coming from languages like Python, Java, etc. In this post, we will learn about what it means to Copy and Clone in Rust.

Ownership in Rust

Before discussing Copy and Clone traits in rust let’s briefly understand the ownership first. In every programming language, there are ways to manage the computer’s memory while executing. Language-supporting garbage collector regularly looks for no longer used memory is the program executes, while in other languages like C/C++, programmers must explicitly allocate and free the memory.

In Rust, the memory is managed through ownership. Ownership is the set of rules that the compiler checks to manage memory. If any of the ownership rules are violated the program won’t even compile.

Ownership Rules

Because ownership is a new concept for many programmers, it does take some time to get used to, but keeping these rules in mind will help to write code that is safe and efficient.

  1. In Rust each value has an owner, that is the variable assigned to it.
  2. There can be only one owner at a time. Although, multiple variables can hold a reference to or borrow the same value – but that value will only have one owner
  3. When the owner goes out of scope the value will be dropped.

Memory Allocation in Rust (Stack vs Heap)

Rust provides both the Stack and Heap part of memory at runtime. In Rust, it is important to understand memory allocation because how values are stored in memory affects how the language will behave and helps programmers in making certain decisions.

The way value is stored in Heap and Stack is different. Just like stack data structures, Stack stores the value in the order, it gets it and removes the values in the opposite order, i.e., Last In First Out order. In Heap when we want to store data, we request a certain amount of space. The memory allocator finds an empty spot in the heap big enough to store the value, marks it in use, and returns a pointer to the address of that location.

Pushing to the stack is faster than allocating on the heap because the allocator never has to search for a place to store new data.

Values like: u16, u32, i32, and f64 are all stored in a stack because their size is known at compile time.

Dynamic size types like String and Vec are stored in the heap because they can grow or shrink in size and don’t have a fixed size.

Clone trait in Rust

In Rust, some simple types are “implicitly copyable” and when you assign them or pass them as arguments, the receiver will get a copy, leaving the original value in place. For other types, copies must be made explicitly, by implementing the Clone trait and calling the clone() method.

The Clone trait defines the ability to explicitly create a deep copy of an object T. When we call Clone for type T, it does all the arbitrarily complicated operations required to create a new T.

fn main() {
    let name = String::fron("IntMain!");
    //ownership of value is transferred from name to new_name 
    let new_name = name;
    //error: name was moved!
    println!("Old name = {} and new name ={}", name, new_name);
}

In the above example according to the ownership rules, the assignment of a name to new_name transferred the ownership of the String instance to new_name and since there can only be one owner hence name was dropped. Hence to have a deep copy we need to explicitly call clone() method.

fn main() { 
    let name = String::fron("IntMain!"); 

    //Deep copy of name is allocated to new_name
    //explicit duplication of an object  
    let new_name = name.clone(); 

    //Compiles fine with no erros 
    println!("Old name = {} and New name ={}", name, new_name); }
}

Due to deep copy both name and new_name are free to independently drop their heap buffer.

Note: The Clone trait doesn’t always create a deep copy. Types are free to implement Clone in any way they want. For example, Rc and Arc only increment a reference count instead of creating a deep copy.

Copy trait in Rust

The Copy trait in rust defines the ability to implicitly copy an object. The behavior Copy is not overloadable. It is always a simple bitwise copy. This is available for the types that have a fixed size and are stored entirely on the stack.

fn main() { 
    let num = 987; 
    //new_num is a copy of num 
    let new_num = 987; 

    //Compiles fine with no erros
    println!("Old num = {} and New num ={}", nun, new_num); }
}

The above example is not contradiciting the ownership rules, becuase i32 are Copy type as they are stored in stack and it is easy to copy them, hence value of num is implicity copied to new_num. As we can imagine not every type can implement Copy, the best example is String which implement Clone but not Copy.

The copy type is only applicated to types that are stored in stack, like integers, floats, structs with all their fields Copy of type.

//This stuct implements Copy trait as 
//all of its field are of Copy type
#[derive(Clone, Copy)]
struct copy_and_cloneable{
    num1: i32,
    num2: i32,
    num3: bool,
}

//This stuct doen't implements Copy trait as 
//String is not a Copy type
#[derive(Clone, Copy)]
stuct cloneable_only{
    num1: i32,
    name: String,     //Not a Copy type
}

Note: Clone is a supertrait of Copy, so everything which implements Copy must also implement Clone, hence when a type implements Copy the Clone implementation is just returning *self.

Conclusion

In rust it is easy to understand the difference between Copy and Clone once you understand the Rust memory allocation. Types that can be pushed into stack, implements the Copy trait and types that can be pushed into the heap implements the Clone trait. Since deep copy is expensive hence we need to explicitally invoke clone() method, otherwise move happens by default. Also, Clone can perform anything from simple stack copy of few bytes to a heap copy of huge vectors.

LEAVE A REPLY

Please enter your comment!
Please enter your name here