Menu
Coddy logo textTech

Clone y Copy

Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 37 de 61.

En Rust, cuando asignas un valor a otra variable, la propiedad (ownership) generalmente se mueve: la variable original se vuelve inválida. Sin embargo, dos traits estándar cambian este comportamiento: Clone y Copy.

El trait Copy permite el copiado bit a bit implícito. Cuando un tipo implementa Copy, asignarlo a otra variable crea una copia automática en lugar de mover la propiedad:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 se copia, no se mueve

println!("{}, {}", p1.x, p2.x);  // ¡Ambos son válidos!

El trait Clone proporciona copia profunda explícita a través del método .clone(). Es necesario siempre que derives Copy, pero también se puede usar por sí solo para tipos que necesitan una copia explícita:

let p3 = p1.clone();  // Copia explícita

Hay una restricción importante: Copy solo puede derivarse para tipos en los que todos los campos también implementen Copy. Los tipos simples como los enteros y los flotantes son Copy, pero String no lo es; este gestiona memoria en el montón (heap). Si tu struct contiene un String, solo puedes derivar Clone, no Copy.

RasgoComportamientoUso
CopyImplícito, automáticoDatos simples solo en pila
CloneExplícito mediante .clone()Cualquier dato duplicable

Para structs simples con campos primitivos, derivar ambos traits te permite asignar valores libremente sin preocuparte por la propiedad (ownership).

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de coordenadas que demuestre la diferencia entre los traits Copy y Clone! Crearás dos structs—uno que se puede copiar implícitamente y otro que requiere una clonación explícita—para ver cómo Rust maneja la duplicación de manera diferente según los traits que derives.

Organizarás tu código en dos archivos:

  • coordinates.rs: Define dos structs públicos que representen diferentes tipos de coordenadas:
    • GridPoint — con campos públicos x e y (ambos i32). Dado que solo contiene tipos primitivos, deriva tanto Copy como Clone para que pueda copiarse implícitamente al ser asignado.
    • NamedLocation — con campos públicos name (String) y x/y (i32). Dado que contiene un String, solo puedes derivar Clone—no Copy. Este struct requerirá llamadas explícitas a .clone() para duplicarse.
  • main.rs: Importa tu módulo de coordenadas y demuestra cómo cada struct se comporta de manera diferente al ser duplicado. Crea instancias utilizando las entradas proporcionadas, luego muestra que:
    • Un GridPoint puede asignarse a otra variable y ambos permanecen válidos (copia implícita)
    • Un NamedLocation debe usar .clone() para crear un duplicado manteniendo el original válido

Tu salida debe mostrar tanto los valores originales como los copiados/clonados para demostrar que ambas variables son válidas después de la duplicación:

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

Por ejemplo, con las entradas 5, 10, y Home:

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

Recibirás tres entradas: la coordenada x (analizada como i32), la coordenada y (analizada como i32), y el nombre de la ubicación.

Hoja de referencia

El trait Copy permite el copiado bit a bit implícito. Cuando un tipo implementa Copy, asignarlo a otra variable crea una copia automática en lugar de mover la propiedad:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 se copia, no se mueve

println!("{}, {}", p1.x, p2.x);  // ¡Ambos son válidos!

El trait Clone proporciona copiado profundo explícito a través del método .clone():

let p3 = p1.clone();  // Copia explícita

Copy solo se puede derivar para tipos donde todos los campos también implementan Copy. Los tipos simples como enteros y flotantes son Copy, pero String no lo es. Si tu struct contiene un String, solo puedes derivar Clone, no Copy.

TraitComportamientoUso
CopyImplícito, automáticoDatos simples solo en pila (stack)
CloneExplícito mediante .clone()Cualquier dato duplicable

Al derivar Copy, también debes derivar Clone.

Pruébalo tú mismo

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // Leer entradas
    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: Crear una instancia de GridPoint con x e y

    // TODO: Demostrar la copia implícita asignando a otra variable
    // (GridPoint implementa Copy, por lo que esto crea una copia automáticamente)

    // TODO: Imprimir el punto original y el copiado
    // Formato: "Original point: ({x}, {y})"
    // Formato: "Copied point: ({x}, {y})"

    // TODO: Crear una instancia de NamedLocation con name, x e y

    // TODO: Demostrar la clonación explícita (NamedLocation solo implementa Clone, no Copy)
    // Usar .clone() para crear un duplicado

    // TODO: Imprimir la ubicación original y la clonada
    // Formato: "Original location: {name} at ({x}, {y})"
    // Formato: "Cloned location: {name} at ({x}, {y})"
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming