Menu
Coddy logo textTech

Clone and Copy

Part of the Object Oriented Programming section of Coddy's Rust journey — lesson 37 of 61.

In Rust, when you assign a value to another variable, ownership typically moves—the original variable becomes invalid. However, two standard traits change this behavior: Clone and Copy.

The Copy trait enables implicit bitwise copying. When a type implements Copy, assigning it to another variable creates an automatic copy instead of moving ownership:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 is copied, not moved

println!("{}, {}", p1.x, p2.x);  // Both are valid!

The Clone trait provides explicit deep copying through the .clone() method. It's required whenever you derive Copy, but can also be used alone for types that need explicit copying:

let p3 = p1.clone();  // Explicit copy

There's an important restriction: Copy can only be derived for types where all fields also implement Copy. Simple types like integers and floats are Copy, but String is not—it manages heap memory. If your struct contains a String, you can only derive Clone, not Copy.

TraitBehaviorUsage
CopyImplicit, automaticSimple stack-only data
CloneExplicit via .clone()Any duplicatable data

For simple structs with primitive fields, deriving both traits lets you freely assign values without worrying about ownership.

challenge icon

Challenge

Easy

Let's build a coordinate system that demonstrates the difference between Copy and Clone traits! You'll create two structs—one that can be implicitly copied and one that requires explicit cloning—to see how Rust handles duplication differently based on the traits you derive.

You'll organize your code across two files:

  • coordinates.rs: Define two public structs that represent different kinds of coordinates:
    • GridPoint — with public x and y fields (both i32). Since it only contains primitive types, derive both Copy and Clone so it can be implicitly copied when assigned.
    • NamedLocation — with public name (String) and x/y fields (i32). Since it contains a String, you can only derive Clone—not Copy. This struct will require explicit .clone() calls to duplicate.
  • main.rs: Bring in your coordinates module and demonstrate how each struct behaves differently when duplicated. Create instances using the inputs provided, then show that:
    • A GridPoint can be assigned to another variable and both remain valid (implicit copy)
    • A NamedLocation must use .clone() to create a duplicate while keeping the original valid

Your output should show both the original and copied/cloned values to prove both variables are valid after duplication:

Original point: ({x}, {y})
Copied point: ({x}, {y})
Original location: {name} at ({x}, {y})
Cloned location: {name} at ({x}, {y})

For example, with inputs 5, 10, and Home:

Original point: (5, 10)
Copied point: (5, 10)
Original location: Home at (5, 10)
Cloned location: Home at (5, 10)

You will receive three inputs: the x coordinate (parse as i32), the y coordinate (parse as i32), and the location name.

Cheat sheet

The Copy trait enables implicit bitwise copying. When a type implements Copy, assigning it to another variable creates an automatic copy instead of moving ownership:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 is copied, not moved

println!("{}, {}", p1.x, p2.x);  // Both are valid!

The Clone trait provides explicit deep copying through the .clone() method:

let p3 = p1.clone();  // Explicit copy

Copy can only be derived for types where all fields also implement Copy. Simple types like integers and floats are Copy, but String is not. If your struct contains a String, you can only derive Clone, not Copy.

TraitBehaviorUsage
CopyImplicit, automaticSimple stack-only data
CloneExplicit via .clone()Any duplicatable data

When deriving Copy, you must also derive Clone.

Try it yourself

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // Read inputs
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let x: i32 = input1.trim().parse().expect("Invalid number");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let y: i32 = input2.trim().parse().expect("Invalid number");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let name = input3.trim().to_string();

    // TODO: Create a GridPoint instance with x and y

    // TODO: Demonstrate implicit copy by assigning to another variable
    // (GridPoint implements Copy, so this creates a copy automatically)

    // TODO: Print original and copied point
    // Format: "Original point: ({x}, {y})"
    // Format: "Copied point: ({x}, {y})"

    // TODO: Create a NamedLocation instance with name, x, and y

    // TODO: Demonstrate explicit clone (NamedLocation only implements Clone, not Copy)
    // Use .clone() to create a duplicate

    // TODO: Print original and cloned location
    // Format: "Original location: {name} at ({x}, {y})"
    // Format: "Cloned location: {name} at ({x}, {y})"
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming