Menu
Coddy logo textTech

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.

CaratteristicaComportamentoUtilizzo
CopyImplicito, automaticoDati semplici solo nello stack
CloneEsplicito 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à.

challenge icon

Sfida

Facile

Costruiamo 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 pubblici x e y (entrambi i32). Poiché contiene solo tipi primitivi, deriva sia Copy sia Clone, in modo che possa essere copiata implicitamente quando viene assegnata.
    • NamedLocation: con il campo pubblico name (String) e i campi x/y (i32). Poiché contiene una String, puoi derivare solo Clone, non Copy. 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 GridPoint può essere assegnata a un'altra variabile ed entrambe rimangono valide (copia implicita)
    • Per creare un duplicato di una NamedLocation mantenendo valido l'originale, è necessario usare .clone()

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})"
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore Rust online