Clone e Copy
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 37 di 61.
In Rust, quando assegni un valore a un'altra variabile, la proprietà in genere viene trasferita: la variabile originale diventa non valida. Tuttavia, due trait standard modificano questo comportamento: Clone e Copy.
Il trait Copy consente la copia bit a bit implicita. Quando un tipo implementa Copy, assegnarlo a un'altra variabile crea una copia automatica invece di trasferire la proprietà:
#[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!
Il tratto Clone fornisce una copia profonda esplicita tramite il metodo .clone(). È richiesto ogni volta che derivi Copy, ma può anche essere usato da solo per i tipi che richiedono una copia esplicita:
let p3 = p1.clone(); // Copia explícita
C'è una restrizione importante: Copy può essere derivato solo per i tipi in cui tutti i campi implementano anch'essi Copy. I tipi semplici, come gli interi e i numeri in virgola mobile, sono Copy, ma String non lo è. Gestisce la memoria heap. Se la tua struct contiene un String, puoi derivare solo Clone, non Copy.
| Caratteristica | Comportamento | Utilizzo |
|---|---|---|
Copy | Implicito, automatico | Dati semplici solo nello stack |
Clone | Esplicito tramite .clone() | Qualsiasi dato duplicabile |
Per le struct semplici con campi primitivi, derivare entrambi i trait ti permette di assegnare liberamente i valori senza preoccuparti della proprietà.
Sfida
FacileCostruiamo un sistema di coordinate che mostri la differenza tra i trait Copy e Clone! Creerai due struct: una che può essere copiata implicitamente e una che richiede una clonazione esplicita, per vedere come Rust gestisce la duplicazione in modo diverso in base ai trait che derivi.
Organizzerai il codice in due file:
coordinates.rs: Definisci due struct pubbliche che rappresentano diversi tipi di coordinate:GridPoint: con i campi pubblicixey(entrambii32). Poiché contiene solo tipi primitivi, deriva siaCopysiaClone, in modo che possa essere copiata implicitamente quando viene assegnata.NamedLocation: con il campo pubbliconame(String) e i campix/y(i32). Poiché contiene unaString, puoi derivare soloClone, nonCopy. Questa struct richiederà chiamate esplicite a.clone()per essere duplicata.
main.rs: Importa il modulo coordinates e mostra come ciascuna struct si comporta diversamente quando viene duplicata. Crea le istanze usando gli input forniti, poi mostra che:- Una
GridPointpuò essere assegnata a un'altra variabile ed entrambe rimangono valide (copia implicita) - Per creare un duplicato di una
NamedLocationmantenendo valido l'originale, è necessario usare.clone()
- Una
L'output dovrebbe mostrare sia i valori originali sia quelli copiati/clonati, per dimostrare che entrambe le variabili sono valide dopo la duplicazione:
Original point: ({x}, {y})
Copied point: ({x}, {y})
Original location: {name} at ({x}, {y})
Cloned location: {name} at ({x}, {y})Ad esempio, con gli input 5, 10 e Home:
Original point: (5, 10)
Copied point: (5, 10)
Original location: Home at (5, 10)
Cloned location: Home at (5, 10)Riceverai tre input: la coordinata x (da analizzare come i32), la coordinata y (da analizzare come i32) e il nome della località.
Provalo tu
mod coordinates;
use coordinates::{GridPoint, NamedLocation};
fn main() {
// Leggi gli input
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: Crea un'istanza di GridPoint con x e y
// TODO: Mostra la copia implicita assegnando il valore a un'altra variabile
// (GridPoint implementa Copy, quindi viene creata automaticamente una copia)
// TODO: Stampa il punto originale e quello copiato
// Formato: "Original point: ({x}, {y})"
// Formato: "Copied point: ({x}, {y})"
// TODO: Crea un'istanza di NamedLocation con name, x e y
// TODO: Mostra la clonazione esplicita (NamedLocation implementa solo Clone, non Copy)
// Usa .clone() per creare un duplicato
// TODO: Stampa la posizione originale e quella clonata
// Formato: "Original location: {name} at ({x}, {y})"
// Formato: "Cloned location: {name} at ({x}, {y})"
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online