Menu
Coddy logo textTech

Clone e Copy

Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 37 de 61.

Em Rust, quando você atribui um valor a outra variável, a posse (ownership) normalmente é movida — a variável original torna-se inválida. No entanto, duas traits padrão alteram esse comportamento: Clone e Copy.

O trait Copy permite a cópia bit a bit implícita. Quando um tipo implementa Copy, atribuí-lo a outra variável cria uma cópia automática em vez de mover a posse (ownership):

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 é copiado, não movido

println!("{}, {}", p1.x, p2.x);  // Ambos são válidos!

A trait Clone fornece cópia profunda explícita através do método .clone(). É necessário sempre que você deriva Copy, mas também pode ser usado sozinho para tipos que precisam de cópia explícita:

let p3 = p1.clone();  // Cópia explícita

Há uma restrição importante: Copy só pode ser derivado para tipos onde todos os campos também implementam Copy. Tipos simples como inteiros e floats são Copy, mas String não é — ele gerencia memória heap. Se sua struct contém uma String, você só pode derivar Clone, não Copy.

TraitComportamentoUso
CopyImplícito, automáticoDados simples apenas na stack
CloneExplícito via .clone()Qualquer dado duplicável

Para structs simples com campos primitivos, derivar ambos os traits permite que você atribua valores livremente sem se preocupar com ownership.

challenge icon

Desafio

Fácil

Vamos construir um sistema de coordenadas que demonstra a diferença entre as traits Copy e Clone! Você criará duas structs—uma que pode ser copiada implicitamente e outra que requer clonagem explícita—para ver como o Rust lida com a duplicação de forma diferente com base nas traits que você deriva.

Você organizará seu código em dois arquivos:

  • coordinates.rs: Defina duas structs públicas que representam diferentes tipos de coordenadas:
    • GridPoint — com campos públicos x e y (ambos i32). Como ele contém apenas tipos primitivos, derive tanto Copy quanto Clone para que ele possa ser copiado implicitamente quando atribuído.
    • NamedLocation — com campos públicos name (String) e x/y (i32). Como ele contém uma String, você só pode derivar Clone—não Copy. Esta struct exigirá chamadas explícitas a .clone() para ser duplicada.
  • main.rs: Importe seu módulo de coordenadas e demonstre como cada struct se comporta de forma diferente ao ser duplicada. Crie instâncias usando as entradas fornecidas e, em seguida, mostre que:
    • Um GridPoint pode ser atribuído a outra variável e ambos permanecem válidos (cópia implícita)
    • Um NamedLocation deve usar .clone() para criar uma duplicata enquanto mantém o original válido

Sua saída deve mostrar tanto os valores originais quanto os copiados/clonados para provar que ambas as variáveis são válidas após a duplicação:

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

Por exemplo, com as entradas 5, 10, e Home:

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

Você receberá três entradas: a coordenada x (converta para i32), a coordenada y (converta para i32) e o nome do local.

Folha de consulta

A trait Copy permite a cópia bitwise implícita. Quando um tipo implementa Copy, atribuí-lo a outra variável cria uma cópia automática em vez de mover a posse (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!

A trait Clone fornece cópia profunda (deep copy) explícita através do método .clone():

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

Copy só pode ser derivado para tipos onde todos os campos também implementam Copy. Tipos simples como inteiros e floats são Copy, mas String não é. Se sua struct contém uma String, você só pode derivar Clone, não Copy.

TraitComportamentoUso
CopyImplícito, automáticoDados simples apenas na stack
CloneExplícito via .clone()Qualquer dado duplicável

Ao derivar Copy, você também deve derivar Clone.

Experimente você mesmo

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // Ler 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: Criar uma instância de GridPoint com x e y

    // TODO: Demonstrar cópia implícita atribuindo a outra variável
    // (GridPoint implementa Copy, então isso cria uma cópia automaticamente)

    // TODO: Imprimir o ponto original e o copiado
    // Format: "Original point: ({x}, {y})"
    // Format: "Copied point: ({x}, {y})"

    // TODO: Criar uma instância de NamedLocation com name, x, e y

    // TODO: Demonstrar clone explícito (NamedLocation apenas implementa Clone, não Copy)
    // Usar .clone() para criar uma duplicata

    // TODO: Imprimir a localização original e a clonada
    // Format: "Original location: {name} at ({x}, {y})"
    // Format: "Cloned location: {name} at ({x}, {y})"
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Object Oriented Programming