Menu
Coddy logo textTech

Clone und Copy

Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 37 von 61.

In Rust wird der Besitz (Ownership) normalerweise übertragen, wenn Sie einen Wert einer anderen Variablen zuweisen – die ursprüngliche Variable wird ungültig. Zwei Standard-Traits ändern dieses Verhalten jedoch: Clone und Copy.

Das Copy-Trait ermöglicht implizites bitweises Kopieren. Wenn ein Typ Copy implementiert, erzeugt die Zuweisung an eine andere Variable eine automatische Kopie, anstatt den Besitz zu verschieben:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 wird kopiert, nicht verschoben

println!("{}, {}", p1.x, p2.x);  // Beide sind gültig!

Der Clone-Trait bietet explizites tiefes Kopieren durch die .clone()-Methode. Er wird immer dann benötigt, wenn man Copy ableitet, kann aber auch allein für Typen verwendet werden, die explizites Kopieren erfordern:

let p3 = p1.clone();  // Explizite Kopie

Es gibt eine wichtige Einschränkung: Copy kann nur für Typen abgeleitet werden, bei denen alle Felder ebenfalls Copy implementieren. Einfache Typen wie Integer und Floats sind Copy, aber String ist es nicht – es verwaltet Heap-Speicher. Wenn dein Struct ein String enthält, kannst du nur Clone ableiten, nicht Copy.

MerkmalVerhaltenVerwendung
CopyImplizit, automatischEinfache Stack-Daten
CloneExplizit über .clone()Beliebige duplizierbare Daten

Für einfache Structs mit primitiven Feldern ermöglicht das Ableiten beider Traits, Werte frei zuzuweisen, ohne sich um Ownership kümmern zu müssen.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Koordinatensystem bauen, das den Unterschied zwischen den Traits Copy und Clone demonstriert! Sie werden zwei Structs erstellen – eines, das implizit kopiert werden kann, und eines, das explizites Klonen erfordert –, um zu sehen, wie Rust die Duplizierung basierend auf den von Ihnen abgeleiteten Traits unterschiedlich handhabt.

Sie werden Ihren Code auf zwei Dateien aufteilen:

  • coordinates.rs: Definieren Sie zwei öffentliche Structs, die verschiedene Arten von Koordinaten darstellen:
    • GridPoint — mit öffentlichen Feldern x und y (beide i32). Da es nur primitive Typen enthält, leiten Sie sowohl Copy als auch Clone ab, damit es bei einer Zuweisung implizit kopiert werden kann.
    • NamedLocation — mit öffentlichen Feldern name (String) und x/y (i32). Da es einen String enthält, können Sie nur Clone ableiten – nicht Copy. Dieses Struct erfordert explizite .clone()-Aufrufe zur Duplizierung.
  • main.rs: Binden Sie Ihr Koordinaten-Modul ein und demonstrieren Sie, wie sich jedes Struct bei der Duplizierung unterschiedlich verhält. Erstellen Sie Instanzen unter Verwendung der bereitgestellten Eingaben und zeigen Sie dann:
    • Ein GridPoint kann einer anderen Variablen zugewiesen werden und beide bleiben gültig (implizite Kopie)
    • Ein NamedLocation muss .clone() verwenden, um ein Duplikat zu erstellen, während das Original gültig bleibt

Ihre Ausgabe sollte sowohl die ursprünglichen als auch die kopierten/geklonten Werte anzeigen, um zu beweisen, dass beide Variablen nach der Duplizierung gültig sind:

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

Zum Beispiel mit den Eingaben 5, 10 und Home:

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

Sie erhalten drei Eingaben: die x-Koordinate (als i32 parsen), die y-Koordinate (als i32 parsen) und den Standortnamen.

Spickzettel

Der Copy-Trait ermöglicht implizites bitweises Kopieren. Wenn ein Typ Copy implementiert, erstellt das Zuweisen an eine andere Variable eine automatische Kopie, anstatt den Besitz zu verschieben:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 wird kopiert, nicht verschoben

println!("{}, {}", p1.x, p2.x);  // Beide sind gültig!

Der Clone-Trait bietet explizites tiefes Kopieren durch die .clone()-Methode:

let p3 = p1.clone();  // Explizite Kopie

Copy kann nur für Typen abgeleitet werden, bei denen alle Felder ebenfalls Copy implementieren. Einfache Typen wie Integer und Floats sind Copy, aber String ist es nicht. Wenn Ihr Struct einen String enthält, können Sie nur Clone ableiten, nicht Copy.

TraitVerhaltenVerwendung
CopyImplizit, automatischEinfache Daten, die nur auf dem Stack liegen
CloneExplizit über .clone()Alle duplizierbaren Daten

Wenn Sie Copy ableiten, müssen Sie auch Clone ableiten.

Probier es selbst

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // Eingaben lesen
    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: Erstelle eine GridPoint-Instanz mit x und y

    // TODO: Demonstriere implizites Kopieren durch Zuweisung an eine andere Variable
    // (GridPoint implementiert Copy, daher wird automatisch eine Kopie erstellt)

    // TODO: Gib den ursprünglichen und den kopierten Punkt aus
    // Format: "Original point: ({x}, {y})"
    // Format: "Copied point: ({x}, {y})"

    // TODO: Erstelle eine NamedLocation-Instanz mit name, x und y

    // TODO: Demonstriere explizites Klonen (NamedLocation implementiert nur Clone, nicht Copy)
    // Verwende .clone(), um ein Duplikat zu erstellen

    // TODO: Gib den ursprünglichen und den geklonten Standort aus
    // Format: "Original location: {name} at ({x}, {y})"
    // Format: "Cloned location: {name} at ({x}, {y})"
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Object Oriented Programming