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.
| Cecha | Działanie | Zastosowanie |
|---|---|---|
Copy | Domyślne, automatyczne | Proste dane przechowywane na stosie |
Clone | Jawne 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ść.
Wyzwanie
ŁatwyZbudujmy 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 polamixiy(oba typui32). Ponieważ zawiera wyłącznie typy proste, wyprowadź zarównoCopy, jak iClone, aby można ją było niejawnie kopiować podczas przypisywania.NamedLocation: z publicznym polemname(String) oraz polamix/y(i32). Ponieważ zawieraString, możesz wyprowadzić tylkoClone, a nieCopy. 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ść
GridPointmożna przypisać do innej zmiennej, a obie pozostają prawidłowe (niejawne kopiowanie) - Aby utworzyć duplikat
NamedLocationi zachować prawidłowy oryginał, trzeba użyć.clone()
- Wartość
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})"
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Metody i zachowanie
Wprowadzenie do bloków implementacjiParametr selfMetody modyfikująceFunkcje powiązaneWiele bloków implementacjiŁańcuchowe wywoływanie metodPowtórzenie — działania na prostokącie4Projekt: Wirtualne zwierzątko
Definiowanie zwierzątkaKarmienie zwierzątka7Standardowe cechy
Cecha DebugCecha DisplayClone i CopyCechy równościPowtórka – punkt do wydrukowania10Projekt: System dokumentów
Trait DrawKomponent tekstowy2Hermetyzacja i moduły
Podstawy modułówSłowo kluczowe publicPola prywatneGetterySetteryPodsumowanie — bezpieczna skrytka5Typy generyczne
Struktury generyczneMetody generyczneWiele typów generycznychFunkcje generycznePodsumowanie – punkt współrzędnych8Cechy jako ograniczenia
Składnia ograniczeń cechWiele ograniczeńKlauzula whereZwracanie typów z użyciem cechPodsumowanie — generyczna drukarka11Wzorce projektowe w Rust
Wzorzec NewtypeKompozycjaTrait DropFrom i IntoPodsumowanie — atrapowy inteligentny wskaźnik3Zaawansowane typy wyliczeniowe
Typy wyliczeniowe z danymiMetody typów wyliczeniowychDopasowywanie wariantów danychTyp wyliczeniowy Option — powtórzeniePodsumowanie — typ wyliczeniowy Shape6Definiowanie cech
Czym jest cecha?Implementowanie cechImplementacje domyślneNadpisywanie wartości domyślnychCechy z parametramiPowtórzenie — odtwarzacz multimedialnyPoćwicz samodzielnie: Kompilator Rust online