러스트에서, 값을 할당받은 변수는 그 값의 소유자가 됨
let v: Vec<i32> = Vec::new();
변수가 범위({}사이)를 벗어나면 소유하고 있는 값은 드롭(memory free/return)
소유자는 한 순간에 한 명만 존재
-> 즉, 오직 소유자만이 해당 변수를 드롭시킬 수 있음(double-free
bug 방지)
let v: Vec<i32> = Vec::new();
let v1 = v;//v1 is the new owner
v.len();//error: Use of moved value
근데 소유자만 해당 변수에 할당된 값을 다룰 수 있다면 너무 빡빡함! 프로그래밍 하기 힘듦!
그래서 소유자로부터 참조를 빌릴 수 있는 borrowing이라는 개념이 있음
소유자는 한 순간에 오직 한 명만 있어야 하지만, borrower는 한 순간에 여러 명이 있을 수 있음
let v: Vec<i32> = Vec::new();
let v1 = &v;//v1 has borrowed from v
let v2 = &v;//v2 has also borrowed from v
v.len();//allowed
v1.len();//also allowed
v2.len();//also allowed
대신 소유자가 그 값을 드롭하면, borrower도 그 값에 접근할 수 없음(use-after-free
bug 방지)
let v1: &Vec<i32>;
{
let v = Vec::new();
v1 = &v;
}//v is dropped here
v1.len();//error:borrowed value does not live long enough
동시에 여러 개의 참조가 존재할 수 있지만, 변경가능한 참조는 한 순간에 하나만 있어야 함
let mut v = vec![0, 1, 2, 3];
let v1 = &v[0];//an immutable reference to Vec's first element
v.push(4);//this can invalidate Vec's internal buffer
let v2 = *v1;//this could access invalid memory
러스트는 컴파일 타임에 변수들의 라이프타임을 추적함
non-lexical lifetime이라고, 복잡하게 구현됨!
소유권 이동
let v:Vec<i32> = Vec::new();
let v1 = v;//v1 is the new owner
Vec은 동적인 자료구조이기 때문에 Heap영역에 메모리를 할당받음
더 정확하게 말하자면,
Vec은 {실제 요소가 저장되어 있는 주소/사용가능한 용량/사용중인 용량}을 가리키는 버퍼(포인터) 값이고, 이 버퍼는 스택에 저장됨
실제 요소가 저장되어 있는 곳이 Heap임
위 코드에서처럼 Vec 인스턴스의 소유권을 v1이라는 다른 변수로 이동시키면
스택에 버퍼가 복사된다. 이때, v1만이 heap의 메모리를 드롭시킬 수 있고 v로는 접근할 수 없음
이렇게 함으로써 두 주체(v, v1)가 힙 메모리를 드롭시킬 수 없게 되었다.
소유권 이동은 다른 변수로의 할당, 함수에 인자를 넘길 때, 함수로부터 리턴값을 받을 때, 구조체나 enum의 필드에 값을 할당할 때 일어난다.
복사
값이 힙에 할당되지 않는 변수들.
정확히 말하면 Copy trait을 구현하고 있는 타입들
두 변수는 완전히 독립적임
소유권을 이동시키지 않고 진짜로 deep copy를 하고 싶다면?
let v: Vec<i32> = Vec::new();
let v1 = v.clone();//ok since Vec implements Clone
println!("v's length is {}", v.len());//ok
Clone trait을 구현하면 됨