홈강좌Rust 입문·중급 47편 중 19편째
Rust 가변 참조 — &mut 는 한 번에 하나만 (E0499·E0502)
Rust 에서 빌린 값을 고치려면 &mut 로 빌린다. 규칙은 하나다. 같은 값에 대해 읽기 참조(&)는 여러 개, 가변 참조(&mut)는 딱 하나만 동시에 있을 수 있고, 둘을 섞을 수 없다. 어기면 E0499·E0502 가 난다. 참조를 마지막으로 쓴 뒤라면 새로 빌려도 된다.
01 &mut 로 빌리면 고칠 수 있다
18편 끝의 오류를 고쳐 보자. 세 군데에 mut 가 들어간다.
fn add_suffix(text: &mut String) {
text.push_str("!");
}
fn main() {
let mut name = String::from("ferris");
add_suffix(&mut name);
add_suffix(&mut name);
println!("{name}");
} Compiling suffix v0.1.0 (~/projects/suffix)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/suffix`
ferris!!- 매개변수가
&mut String이다. 고칠 수 있게 빌린다. - 부를 때
&mut name으로 빌려준다. - 주인
name도let mut다. 바꿀 수 없는 값을 고치라고 빌려줄 수는 없다(3편).
두 번 불렀으니 느낌표가 두 개 붙었다. 주인은 여전히 main 의 name 이다.
02 가변 참조는 한 번에 하나다
같은 값을 &mut 로 두 번 빌려 보자.
fn main() {
let mut name = String::from("ferris");
let r1 = &mut name;
let r2 = &mut name;
println!("{r1} {r2}");
}error[E0499]: cannot borrow `name` as mutable more than once at a time
--> src/main.rs:4:14
|
3 | let r1 = &mut name;
| --------- first mutable borrow occurs here
4 | let r2 = &mut name;
| ^^^^^^^^^ second mutable borrow occurs here
5 | println!("{r1} {r2}");
| -- first borrow later used here- 무엇 —
name을 한 번에 두 번 이상 가변으로 빌릴 수 없다(more than once at a time). - 어디 — 3번째 줄이 첫 번째 가변 빌림, 4번째 줄이 두 번째다. 5번째 줄의 밑줄은 "첫 번째 빌림을 그 뒤에도 쓰고 있다" 는 뜻이다. 두 빌림이 겹친다.
- 고치는 법 —
help:는 없다. 겹치지 않게 하나를 다 쓴 뒤에 다음을 빌린다(아래 실습).
둘이 동시에 고칠 수 있으면 한쪽이 고치는 도중에 다른 쪽이 읽거나 고쳐서 값이 엉망이 될 수 있다. Rust 는 이런 일을 컴파일할 때 막는다.
03 읽는 중에는 고칠 수 없다
읽기 참조와 가변 참조를 섞어도 막힌다.
fn main() {
let mut name = String::from("ferris");
let r1 = &name;
let r2 = &mut name;
r2.push_str("!");
println!("{r1}");
}error[E0502]: cannot borrow `name` as mutable because it is also borrowed as immutable
--> src/main.rs:4:14
|
3 | let r1 = &name;
| ----- immutable borrow occurs here
4 | let r2 = &mut name;
| ^^^^^^^^^ mutable borrow occurs here
5 | r2.push_str("!");
6 | println!("{r1}");
| -- immutable borrow later used herer1 이 읽는 동안(3번째 줄에서 빌려 6번째 줄에서 씀) 4번째 줄에서 고치려고 빌렸다. 누가 책을 읽는 사이에 다른 사람이 책장을 찢으면 안 되는 것과 같다.
| 같은 값을 동시에 | 되나 |
|---|---|
& 여러 개 | 된다 (18편) |
&mut 하나 | 된다 |
&mut 둘 이상 | 안 된다 (E0499) |
& 와 &mut 함께 | 안 된다 (E0502) |
04 실습 — 다 쓴 뒤에 빌리면 된다
"동시에" 의 기준은 참조를 마지막으로 쓴 곳까지다. 거기까지만 겹치지 않으면 된다.
fn main() {
let mut name = String::from("ferris");
let r1 = &name;
println!("{r1}");
let r2 = &mut name;
r2.push_str("!");
println!("{r2}");
} Compiling rules v0.1.0 (~/projects/rules)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
Running `target/debug/rules`
ferris
ferris!r1 은 5번째 줄에서 마지막으로 쓰였다. 그 뒤인 7번째 줄에서 &mut 로 빌리니 겹치지 않아 컴파일된다. shared-mut-error 와 비교하면 println!("{r1}") 의 자리만 다르다. 그 줄을 맨 아래로 옮기면 다시 E0502 가 난다.
참조 규칙은 이것으로 끝이다. 다음 편에서는 지금까지 써 온 두 문자열 String 과 &str 이 어떻게 다른지 정리한다.