Clone e Copy
Parte da seção Programação Orientada a Objetos do Journey de Rust da Coddy. Lição 37 de 61.
Em Rust, quando você atribui um valor a outra variável, a propriedade normalmente é movida: a variável original se torna inválida. No entanto, duas traits padrão alteram esse comportamento: Clone e Copy.
A trait Copy possibilita a cópia implícita bit a bit. Quando um tipo implementa Copy, atribuí-lo a outra variável cria uma cópia automática em vez de mover a propriedade:
#[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 por meio do método .clone(). Ela é obrigatória sempre que você deriva Copy, mas também pode ser usada sozinha 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 cujos campos também implementam Copy. Tipos simples, como inteiros e números de ponto flutuante, são Copy, mas String não é. Ele gerencia memória no heap. Se sua struct contiver uma String, você só poderá derivar Clone, não Copy.
| Trait | Comportamento | Uso |
|---|---|---|
Copy | Implícito, automático | Dados simples apenas na pilha |
Clone | Explícito via .clone() | Qualquer dado duplicável |
Para structs simples com campos primitivos, derivar ambas as traits permite que você atribua valores livremente sem se preocupar com a propriedade.
Desafio
FácilVamos criar um sistema de coordenadas que demonstre a diferença entre as traits Copy e Clone! Você criará duas structs, uma que pode ser copiada implicitamente e outra que exige clonagem explícita, para ver como Rust trata a duplicação de maneira diferente com base nas traits derivadas.
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úblicosxey(ambosi32). Como ela contém apenas tipos primitivos, derive tantoCopyquantoClonepara que possa ser copiada implicitamente quando atribuída.NamedLocation: comnamepúblico (String) e camposx/y(i32). Como ela contém umaString, você só pode derivarClone, nãoCopy. Essa 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 maneira diferente quando duplicada. Crie instâncias usando as entradas fornecidas e, em seguida, mostre que:- Um
GridPointpode ser atribuído a outra variável e ambas continuam válidas (cópia implícita) - Um
NamedLocationdeve usar.clone()para criar uma duplicata mantendo o original válido
- Um
Sua saída deve mostrar os valores original e copiado/clonado 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 (analise como i32), a coordenada y (analise como i32) e o nome da localização.
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: Crie uma instância de GridPoint com x e y
// TODO: Demonstre a cópia implícita atribuindo a outra variável
// (GridPoint implementa Copy, então isso cria uma cópia automaticamente)
// TODO: Imprima o ponto original e o copiado
// Format: "Original point: ({x}, {y})"
// Formato: "Copied point: ({x}, {y})"
// TODO: Crie uma instância de NamedLocation com name, x e y
// TODO: Demonstre o clone explícito (NamedLocation só implementa Clone, não Copy)
// Use .clone() para criar uma duplicata
// TODO: Print original and cloned location
// Format: "Original location: {name} at ({x}, {y})"
// Format: "Cloned location: {name} at ({x}, {y})"
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Métodos e Comportamento
Introdução a Blocos de ImplementaçãoO Parâmetro SelfMétodos MutáveisFunções AssociadasMúltiplos Blocos de ImplementaçãoEncadeamento de MétodosRecapitulação - Ações de Retângulo4Projeto: Pet Virtual
Definindo o PetAlimentando o Pet7Traits Padrão
A Trait DebugA Trait DisplayClone e CopyTraits de IgualdadeRecapitulação - Ponto Imprimível10Projeto: Sistema de Documentos
A Trait DrawComponente de Texto2Encapsulamento e Módulos
Fundamentos de MódulosA Palavra-chave PublicCampos PrivadosGettersSettersRecapitulação - Cofre Seguro5Genéricos
Structs GenéricasMétodos GenéricosMúltiplos Tipos GenéricosFunções GenéricasRecapitulação - Ponto de Coordenada8Traits como Restrições
Sintaxe de Restrições de TraitRestrições MúltiplasA Cláusula WhereRetornando Tipos com TraitsRecapitulação - Impressora Genérica11Padrões de Projeto em Rust
Padrão NewtypeComposiçãoA Trait DropFrom e IntoRecapitulação - Mock de Smart Pointer3Enums Avançados
Enums com DadosMétodos em EnumsCorrespondência de Variantes de DadosO Enum Option RevisitadoRecapitulação - Enum Shape6Definição de Traits
O que é uma Trait?Implementando TraitsImplementações PadrãoSobrescrevendo PadrõesTraits com ParâmetrosRecapitulação - Media PlayerPratique por conta própria: Compilador de Rust online