Menu
Coddy logo textTech

Clone i Copy

Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 37 z 61.

W Rust, gdy przypisujesz wartość do innej zmiennej, własność zazwyczaj zostaje przeniesiona: pierwotna zmienna staje się nieprawidłowa. Jednak dwa standardowe trait’y zmieniają to zachowanie: Clone i Copy.

Cecha Copy umożliwia niejawną kopię bitową. Gdy typ implementuje Copy, przypisanie go do innej zmiennej automatycznie tworzy kopię zamiast przenosić własność:

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 jest kopiowane, a nie przenoszone

println!("{}, {}", p1.x, p2.x);  // Oba są poprawne!

Cecha Clone zapewnia jawne kopiowanie głębokie za pomocą metody .clone(). Jest wymagana zawsze, gdy wyprowadzasz Copy, ale można jej też używać samodzielnie dla typów, które wymagają jawnego kopiowania:

let p3 = p1.clone();  // Jawna kopia

Istnieje ważne ograniczenie: cechę Copy można wyprowadzić tylko dla typów, których wszystkie pola również implementują Copy. Proste typy, takie jak liczby całkowite i zmiennoprzecinkowe, implementują Copy, ale String nie. Zarządza pamięcią na stercie. Jeśli Twoja struktura zawiera String, możesz wyprowadzić tylko Clone, a nie Copy.

CechaDziałanieZastosowanie
CopyDomyślne, automatyczneProste dane przechowywane na stosie
CloneJawne za pomocą .clone()Dowolne dane, które można skopiować

W przypadku prostych struktur z polami typów podstawowych wyprowadzenie obu tych cech pozwala swobodnie przypisywać wartości bez martwienia się o własność.

challenge icon

Wyzwanie

Łatwy

Zbudujmy układ współrzędnych, który pokaże różnicę między cechami Copy i Clone! Utworzysz dwie struktury: jedną, którą można niejawnie skopiować, i drugą, która wymaga jawnego klonowania. Dzięki temu zobaczysz, jak Rust różnie obsługuje duplikowanie w zależności od wyprowadzonych cech.

Rozmieścisz swój kod w dwóch plikach:

  • coordinates.rs: Zdefiniuj dwie publiczne struktury reprezentujące różne rodzaje współrzędnych:
    • GridPoint: z publicznymi polami x i y (oba typu i32). Ponieważ zawiera wyłącznie typy proste, wyprowadź zarówno Copy, jak i Clone, aby można ją było niejawnie kopiować podczas przypisywania.
    • NamedLocation: z publicznym polem name (String) oraz polami x/y (i32). Ponieważ zawiera String, możesz wyprowadzić tylko Clone, a nie Copy. Ta struktura będzie wymagać jawnych wywołań .clone(), aby utworzyć duplikat.
  • main.rs: Dołącz moduł współrzędnych i pokaż, jak każda struktura zachowuje się inaczej podczas duplikowania. Utwórz instancje przy użyciu podanych danych wejściowych, a następnie pokaż, że:
    • Wartość GridPoint można przypisać do innej zmiennej, a obie pozostają prawidłowe (niejawne kopiowanie)
    • Aby utworzyć duplikat NamedLocation i zachować prawidłowy oryginał, trzeba użyć .clone()

Wynik powinien zawierać zarówno oryginalne, jak i skopiowane/sklonowane wartości, aby potwierdzić, że obie zmienne są prawidłowe po duplikowaniu:

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

Na przykład dla danych wejściowych 5, 10 i Home:

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

Otrzymasz trzy dane wejściowe: współrzędną x (parsowaną jako i32), współrzędną y (parsowaną jako i32) oraz nazwę lokalizacji.

Spróbuj swoich sił

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // Odczytaj dane wejściowe
    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: Utwórz instancję GridPoint z x i y

    // TODO: Zademonstruj niejawne kopiowanie przez przypisanie do innej zmiennej
    // (GridPoint implementuje Copy, więc kopia powstaje automatycznie)

    // TODO: Wypisz oryginalny i skopiowany punkt
    // Format: "Original point: ({x}, {y})"
    // Format: "Copied point: ({x}, {y})"

    // TODO: Utwórz instancję NamedLocation z name, x i y

    // TODO: Zademonstruj jawne klonowanie (NamedLocation implementuje tylko Clone, a nie Copy)
    // Użyj .clone(), aby utworzyć kopię

    // TODO: Wypisz oryginalną i sklonowaną lokalizację
    // Format: "Original location: {name} at ({x}, {y})"
    // Format: "Cloned location: {name} at ({x}, {y})"
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Rust online