[1. 개요]
값의 소유권을 넘기는 대신 개체애 대한 참조자를 사용하는 방법
변수 타입 앞에 & 을 표기한다.
let s1 = String::from("hello");
let len = calculate_length(&s1); // s1 의 값을 참조하지만, 소유하지는 않는다.
주의 할 점은 참조자의 실 소유권이 사용 중 소멸되지 않아야 한다.
함수의 파라미터로 참조자를 만든 것을 빌림 이라고 한다.
참조자 역시 기본적으로 불변한다.
[2. 가변 참조자]
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) { // &String -> &mut String
some_string.push_str(", world");
}
가변 참조자는 한가지 제한 사항이 있다.
특정 스코프 내 특정 데이터에 대한 가변참조자는 딱 하나만 존재 할 수 있다.
=> 이를 통해 컴파일 타임에 Data race 를 방지 할 수 있게 한다.
Data race 는 아래와 같은 상황에서 발생한다.
- 두 개 이상의 포인터가 동시에 같은 데이터에 접근
- 이 중 적어도 하나의 포인터가 데이터를 write 한다.
- 데이터에 접근하는데 동기화를 하는 어떠한 메커니즘이 없다.
동시에 여러 가변 참조자는 만들 수 없기에
스코프 내 새로운 스코프를 열면, 여러 번 가변 참조자를 만들 수 있다.
가변 참조자와 불변 참조자를 혼용 할 수 없다.
=> 불변 참조자 사용 중 값이 바귀는 것을 허용하지 않는다.
이는 컴파일 시점에 확인 할 수 있다.
[3. Dangling 참조자]
해제된 메모리를 가리키는 포인터
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello"); // 힙에 변수 할당
&s // 참조자 반환,
}
// 변수 s 는 소멸
위 코드는 컴파일 되지 않는다.
[4. 정리]
어떤 변수에 대한 참조자는 아래와 같은 경우에만 사용 할 수 있다.
- 하나의 가변 참조자
- 여러개의 불변 참조자들
또한, 참조자는 항상 유효해야 한다.
(참조자가 가리키는 메모리는 항상 유효해야 한다.)