Reference & Borrowing
참조와 차용
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
s1을 선언하고 calculate_length()참수를 호출할 때 사용된 파라미터는 s1의 값을 참조하는 &s1이다. &기호(ampersands)는 참조를 나타내며, 참조는 소유권을 이전하지 않고도 해당 값을 사용할 수 있도록 한다. 따라서 calculate_length의 아규먼트인 s는 아래와 같이 s1을 참조하게 된다.
Reference 참조 (&)와 반대되는 것이 dereference 역참조(*)이며, 이는 나중에 역참조 연산자를 다룰 때 다시 살펴보겠다.
1) 불변참조 Immutable reference
위에 설명한 바와 같이 참조는 기본적으로 불변한다. 따라서 아래와 같이 호출한 함수안에서 불변참조를 수정하려고 하면 에러가 발생한다.
fn main() {
let s = String::from("hello");
change(&s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
error[E0596]: Cannot borrow immutable local variable `some_string` as mutable
2) 가변참조 Mutable reference
가변참조를 사용하기 위해서는 mut로 선언된 변수와 이를 파라미터로 사용하는 함수를 호출해야 한다.
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world"); // no prob
}
그러나 주의할 점은
가변참조는 한번만 가능하다.
let mut s = String::from("hello");
let r1 = &mut s; // ------ first mutable borrow occurs here
let r2 = &mut s; // ^^^^^^ second mutable borrow occurs here
println!("{}, {}", r1, r2); // -- first borrow later used here
error[E0499]: cannot borrow `s` as mutable more than once at a time
대부분의 언어에서는 원할 때 마다 데이터 값을 변경할 수 있는 것과 달리, Rust에서는 여러 가변 참조를 동시에 금지하며 매우 통제된 방식으로 변경을 허용하고 있다. 이로 인한 이점은 데이터 경합을 방지할 수 있다는 것이다. 데이터 경합은 경쟁조건과 유사하며 다음 세 가지 동작이 발생할 때 적용된다.
- 두 개 이상의 포인터가 동시에 동일한 데이터에 액세스할 때
- 적어도 하나의 포인터가 데이터를 쓰는데 사용되고 있을 때
- 데이터 액세스를 동기화하는데 사용되는 매커니즘이 없을 때
데이터 경합은 정의되지 않은 동작을 유발하며 런타임 시 추적의 어려움이 있다. Rust는 데이터 경합으로 코드를 컴파일하는 것을 거부함으로써 이 문제를 방지한다. 동시참조 대신에 여러 가변참조를 허용하기 위해 '중괄호'를 사용할 수 있다.
let mut s = String::from("hello");
{
let r1 = &mut s;
} // r1의 사용범위는 여기서 끝나기 때문에 새로운 참조를 하는데 지장이 없다.
let r2 = &mut s;
불변참조가 있는 동안 가변참조를 가질 수 없다.
let mut sss = String::from("가변참조");
let r1 = &sss; // no prob -- immutable borrow occurs here
let r2 = &sss; // no prob
let r3 = &mut sss; // big prob ^^^^^^ mutable borrow occurs here
println!("{}, {}, and {}", r1, r2, r3); // -- immutable borrow later used here
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
불변참조를 사용하는 동안은 데이터가 변경될 것이라고 예상하지 않기 때문에 여러 불변참조를 사용 가능하다. 그러니 예상 밖으로, 불변참조 중간에 가변참조를 사용하는 것을 막고 있다.
불변참조는 마지막으로 사용된 위치에서 사용범위가 끝나기 때문에, 사용된 이 후에는 가변참조를 사용할 수 있다.
let mut ssss = String::from("가변참조");
let r1 = &ssss; // no prob
let r2 = &ssss; // no prob
println!("{r1}, {r2}"); // 불변참조의 볌위는 마지막으로 사용된 위치에서 끝난다.
let r3 = &mut ssss; // 따라서 여기는 문제가 되지 않는다.
println!("r3 가변참조 : {r3}");
3) 매달린 참조 Dangling reference
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> String {
let s = String::from("dangle");
&s // s는 이 함수에서 생성된 것이므로 이 함수가 끝나면 값이 해제되는데
//해제되는 값의 참조를 반환하기 때문에 문제가 된다.
}
error[E0106]: missing lifetime specifier
s는 이 함수에서 생성된 것이므로 이 함수가 끝나면 값이 해제되는데 해제되는 값의 참조를 반환하기 때문에 문제가 된다.
따라서 이럴 때는 아래와 같이, 참조값이 아닌 실제 값을 반환해주어야 한다.
fn no_dangle() -> String {
let s = String::from("hello");
s
}
'Language > Rust' 카테고리의 다른 글
[Rust]Structure 구조체 (0) | 2022.12.28 |
---|---|
[Rust]소유권 - string slice (0) | 2022.12.28 |
[Rust]Ownership 소유권 (0) | 2022.12.23 |
[Rust]Control Flow 제어문 (0) | 2022.12.22 |
[Rust]Functions:Statements&Expressions (0) | 2022.12.22 |