hyunsu blog

홈강좌Rust 입문·중급 47편 중 18편째

Rust 참조와 빌림 — & 를 붙이면 주인을 넘기지 않고 빌려준다

목차 · 3
  1. 01& 를 붙이면 빌려준다
  2. 02읽기만 하는 참조는 여러 개여도 된다
  3. 03실습 — 빌린 값을 고치려 하면

Rust 에서 &name 처럼 & 를 붙이면 값의 주인은 그대로 두고 참조만 넘긴다. 이것을 빌림(borrowing)이라 한다. 빌린 쪽은 값을 읽을 수만 있어서, 고치려 하면 E0596 이 난다. 읽기만 하는 참조는 여러 개를 동시에 만들어도 된다.

01 & 를 붙이면 빌려준다

이름의 글자 수를 세는 함수를 만들어 보자. 17편이었다면 이름을 넘기는 순간 주인이 바뀌어서, 함수가 끝난 뒤에는 이름을 쓸 수 없었다.

rust
fn length(text: &String) -> usize {
    text.len()
}

fn main() {
    let name = String::from("ferris");
    let n = length(&name);
    println!("{name} has {n} letters");
}
text
   Compiling length v0.1.0 (~/projects/length)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/length`
ferris has 6 letters
  • 매개변수 타입 &String 은 "String 의 참조" 다. 주인이 되는 String 이 아니라 빌린 것이다.
  • 부를 때도 length(&name) 처럼 & 를 붙인다. "name 을 빌려준다" 는 뜻이다.
  • 함수가 끝나면 참조만 사라진다. 빌린 것이라 값을 치우지 않는다. 그래서 main 에서 name 을 계속 쓸 수 있다.

text.len() 은 글자 수(정확히는 바이트 수, 21편)를 usize 로 돌려준다. 그래서 반환 타입이 usize 다(5편).

참조는 친구에게 책을 빌려주는 것과 같다. 친구는 책을 읽을 수 있지만, 책의 주인은 여전히 나다. 친구가 읽고 나면 책은 내게 그대로 있다.

02 읽기만 하는 참조는 여러 개여도 된다

rust
fn main() {
    let name = String::from("ferris");
    let r1 = &name;
    let r2 = &name;
    println!("{r1} {r2} {name}");
}
text
   Compiling length v0.1.0 (~/projects/length)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/length`
ferris ferris ferris

r1 과 r2 가 동시에 name 을 빌렸고, 주인 name 도 그대로 쓸 수 있다. 모두 읽기만 하니 서로 방해할 일이 없다. 책 한 권을 여럿이 함께 보는 것과 같다.

03 실습 — 빌린 값을 고치려 하면

빌린 이름 뒤에 느낌표를 붙여 보자. push_str 은 String 뒤에 글자를 덧붙이는 메서드다.

rust
fn add_suffix(text: &String) {
    text.push_str("!");
}

fn main() {
    let name = String::from("ferris");
    add_suffix(&name);
    println!("{name}");
}
text
error[E0596]: cannot borrow `*text` as mutable, as it is behind a `&` reference
 --> src/main.rs:2:5
  |
2 |     text.push_str("!");
  |     ^^^^ `text` is a `&` reference, so it cannot be borrowed as mutable
  |
help: consider changing this to be a mutable reference
  |
1 | fn add_suffix(text: &mut String) {
  |                      +++
  1. 무엇 — *text 를 고칠 수 있게(mutable) 빌릴 수 없다. & 참조 뒤에 있기 때문이다. *text 는 "text 가 가리키는 값" 이라는 뜻이다.
  2. 어디 — 2번째 줄 text.push_str. text 는 & 참조라서 고칠 수 없다고 다시 말해 준다.
  3. 고치는 법 — help: 가 1번째 줄의 매개변수를 &mut String 으로 바꾸라고 한다. +++ 자리에 mut 를 넣는 것이다.

3편에서 변수는 기본이 "못 바꿈" 이었다. 참조도 같다. & 는 읽기만 하는 참조이고, 고치려면 고칠 수 있는 참조 &mut 가 따로 있다. 바로 고치면 main 쪽도 몇 군데 더 바꿔야 하는데, 그 규칙은 다음 편에서 다룬다.