Clone과 Copy
Coddy Rust 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 37번째.
Rust에서 값을 another 변수에 할당하면 일반적으로 소유권이 이동합니다. 원래 변수는 유효하지 않게 됩니다. 하지만 두 가지 표준 트레이트인 Clone과 Copy가 이러한 동작을 변경합니다.
Copy 트레이트는 암시적 비트 단위 복사를 가능하게 합니다. 어떤 타입이 Copy를 구현하면, 이를 다른 변수에 할당할 때 소유권을 이동하는 대신 자동으로 복사본이 생성됩니다:
#[derive(Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
let p1 = Point { x: 10, y: 20 };
let p2 = p1; // p1은 복사되며, 이동되지 않음
println!("{}, {}", p1.x, p2.x); // 둘 다 유효합니다!
Clone 트레이트는 .clone() 메서드를 통해 explicit 깊은 복사를 제공합니다. Copy를 derive할 때 필요하지만, 명시적인 복사가 필요한 타입에서는 단독으로 사용할 수도 있습니다.
let p3 = p1.clone(); // 명시적 복사
중요한 제한 사항이 있습니다. 모든 필드 또한 Copy를 implement하는 타입에 대해서만 Copy를 derive할 수 있습니다. 정수와 부동 소수점 수 같은 단순한 타입은 Copy이지만, String은 그렇지 않습니다. String은 힙 메모리를 관리합니다. 구조체에 String이 포함되어 있다면 Clone만 derive할 수 있고 Copy는 derive할 수 없습니다.
| 트레이트 | 동작 | 사용 |
|---|---|---|
Copy | 암시적, 자동 | 스택 전용 단순 데이터 |
Clone | .clone()을 통한 명시적 수행 | 복제 가능한 모든 데이터 |
기본형 필드를 가진 간단한 구조체의 경우 두 특성을 모두 파생하면 소유권을 걱정하지 않고 값을 자유롭게 할당할 수 있습니다.
챌린지
쉬움Copy 트레이트와 Clone 트레이트의 차이를 보여 주는 좌표 시스템을 만들어 봅시다! 암시적으로 복사할 수 있는 구조체와 명시적인 클로닝이 필요한 구조체를 각각 하나씩 만들어, 파생하는 트레이트에 따라 Rust가 중복을 서로 다르게 처리하는 방식을 확인합니다.
코드를 두 파일로 나누어 구성합니다:
coordinates.rs: 서로 다른 종류의 좌표를 나타내는 두 개의 public 구조체를 Define합니다:GridPoint: publicx및yfields(둘 다i32)를 가집니다. primitive type만 포함하므로Copy와Clone을 모두 derive하여 할당할 때 암시적으로 복사할 수 있도록 합니다.NamedLocation: publicname(String) 및x/yfields(i32)를 가집니다.String을 포함하므로Copy가 아닌Clone만 derive할 수 있습니다. 이 구조체는 중복을 만들려면 명시적인.clone()호출이 필요합니다.
main.rs: coordinates 모듈을 가져오고 각 구조체가 중복될 때 어떻게 다르게 동작하는지 Demonstrate합니다. 제공된 inputs를 사용해 인스턴스를 만든 다음 다음을 보여 줍니다:GridPoint를 another 변수에 할당해도 두 값이 모두 유효하게 유지됩니다(implicit copy).NamedLocation은 원본을 유효하게 유지하면서 duplicate를 만들려면.clone()을 사용해야 합니다.
중복한 뒤 두 변수가 모두 유효하다는 것을 증명하기 위해 original 및 copied/cloned 값을 모두 출력해야 합니다:
Original point: ({x}, {y})
Copied point: ({x}, {y})
Original location: {name} at ({x}, {y})
Cloned location: {name} at ({x}, {y})예를 들어 inputs가 5, 10, Home인 경우:
Original point: (5, 10)
Copied point: (5, 10)
Original location: Home at (5, 10)
Cloned location: Home at (5, 10)세 개의 inputs를 받습니다: x 좌표(i32로 parse), y 좌표(i32로 parse), 그리고 location name입니다.
직접 해보기
mod coordinates;
use coordinates::{GridPoint, NamedLocation};
fn main() {
// 입력 읽기
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: x와 y로 GridPoint 인스턴스 생성
// TODO: 다른 변수에 할당하여 암시적 복사 시연
// (GridPoint는 Copy를 구현하므로 자동으로 복사본이 생성됩니다)
// TODO: 원본과 복사된 포인트 출력
// Format: "Original point: ({x}, {y})"
// 형식: "Copied point: ({x}, {y})"
// TODO: name, x, y로 NamedLocation 인스턴스 생성
// TODO: 명시적 클론 시연 (NamedLocation은 Clone만 구현하고 Copy는 구현하지 않음)
// .clone()을 사용하여 복제본 생성
// TODO: Print original and cloned location
// Format: "Original location: {name} at ({x}, {y})"
// Format: "Cloned location: {name} at ({x}, {y})"
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Rust 컴파일러