값에는 한 명의 소유자만 있다
Rust는 실행 중 GC 없이도 메모리를 안전하게 정리한다. 컴파일러가 소유자, 이동, 스코프 종료 지점을 미리 검사하기 때문이다.
String 이동은 힙 복사가 아니다
let s2 = s1; 이후 힙 버퍼의 소유자는 s2가 되고, s1은
더 이상 사용할 수 없다.
Heap
buffer왜 s1을 막는가
같은 힙 주소를 두 변수가 해제하면 double free가 되므로, 이전 소유자를 무효화한다.
s1과 s2가 모두 유효하면 스코프 끝에서 같은 힙 버퍼를 중복 해제할 수 있다.
이동 후 s1 사용은 실행 전에 오류가 된다. 런타임 비용 없이 규칙을 지킨다.
마지막 소유자인 s2가 스코프를 벗어날 때 힙 메모리가 정리된다.
대입이 항상 같은 의미는 아니다
스택 값은 Copy, 힙 소유 값은 Move, 명시 복사는 Clone으로 구분한다.
작고 고정된 값
정수처럼 스택에 담기는 단순 값은 복사 후 두 변수 모두 유효하다.
let x = 5; let y = x; // x도 유효
힙 소유권 이동
String은 포인터 메타데이터만 이동하고 기존 변수 사용을 막는다.
let s1 = String::from("hi");
let s2 = s1; // s1 무효
힙 데이터까지 복사
두 버퍼가 모두 필요하면 의도를 드러내며 깊은 복사를 요청한다.
let s2 = s1.clone(); // s1, s2 모두 유효
소유권 생명주기
값은 생성, 이동, 사용, 스코프 종료라는 흐름 안에서 관리된다.
String::from이 힙 버퍼를 확보한다.
s1이 버퍼를 책임진다.
s2 = s1 뒤에는 s2만 유효하다.