지난 레슨이 질문을 남겼어: 왜 어떤 타입은 move 하고 어떤 건 복사해? 답은 두 trait — Copy 와 Clone — 이고, 그 둘 사이의 선은 Rust 의 가장 깔끔한 설계 결정 중 하나야.
Copy — 암묵적, 공짜, 스택 전용
전부 스택에 살고 사소하게 복제 가능한 타입은 Copy trait 을 구현해: 모든 정수랑 부동소수 타입, bool, char, 그리고 Copy 타입만으로 된 튜플이나 배열. 얘들은 let y = x; 가 비트 복사를 하고 x 를 멀쩡히 유효하게 남겨. move 도 호들갑도 없어 — 8 바이트 복제가 소유권 추적보다 싸거든.
Clone — 명시적, 비쌀 수 있음
힙 데이터를 소유하는 타입 (String, 벡터, 해시맵) 은 Copy 를 구현 안 해, 복제하려면 힙 할당이랑 바이트 단위 복사가 필요하니까. 그 비용은 절대 안 보이면 안 되니까 Rust 는 이름으로 요청하게 해: let s2 = s1.clone();. 이제 둘 다 독립된 버퍼를 소유하고 — 그걸 네가 선택한 거야.
.clone() 을 친 거야. 이게 Rust 코드의 성능이 그렇게 읽기 쉬운 이유야 — 비싼 연산이 할당 연산자에 묻히지 않고 또박또박 적혀 있어.derive 로 얻기
네 struct 엔 #[derive(Clone)] 으로 opt-in 해 — 모든 필드가 Copy 면 #[derive(Copy)] 도. 그 한 줄이 컴파일러한테 복제 로직을 대신 생성하라고 시켜. struct 정의 위에 #[derive(Clone, Debug)] 가 붙은 걸 계속 보게 돼.
들일 습관
move 에러를 만나면 게으른 수정은 컴파일될 때까지 .clone() 을 뿌리는 거야. 참아. clone 하나하나가 진짜 할당이야. 종종 옳은 답은 참조 — 다음 트랙 — 인데, 복제 말고 데이터를 빌리는 거야.