hyunsu blog

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

Rust 가림(shadowing) — 같은 이름으로 다시 let 하면 새 변수다

목차 · 4
  1. 01let 을 한 번 더 쓰면 새 변수가 생긴다
  2. 02mut 는 타입을 못 바꾸고, 가림은 바꾼다
  3. 03블록 안에서 가리면 블록이 끝날 때 돌아온다
  4. 04실습 — mut 와 가림 중 무엇을 쓸까

Rust 에서 같은 이름으로 let 을 다시 쓰면, 앞 변수를 가리는 새 변수가 생긴다. 이것을 가림(shadowing)이라 한다. mut 와 달리 타입이 다른 값도 담을 수 있고, 중괄호 블록 안에서 가리면 블록이 끝날 때 원래 값으로 돌아온다.

01 let 을 한 번 더 쓰면 새 변수가 생긴다

정가에서 10% 를 깎는 코드다. mut 없이 let price 를 두 번 썼다.

rust
fn main() {
    let price = 12000;
    println!("정가 {price}원");

    let price = price * 9 / 10;
    println!("할인가 {price}원");
}
text
   Compiling price v0.1.0 (~/projects/price)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/price`
정가 12000원
할인가 10800원

두 번째 let price 는 첫 번째 price 를 바꾼 것이 아니다. 첫 번째 값으로 계산한 새 변수를 같은 이름으로 만든 것이다. 그 뒤로 price 라고 쓰면 새 변수를 가리키고, 첫 번째 변수는 가려져서 더는 보이지 않는다. 새 변수도 mut 가 없으니 다시 못 바꾼다.

값을 한 번 손질한 다음 더는 바꾸지 않을 때 쓴다. discounted_price 같은 새 이름을 지을 필요가 없다.

02 mut 는 타입을 못 바꾸고, 가림은 바꾼다

가격을 숫자로 쓰다가 "12000 won" 이라는 글자로 바꾸고 싶다고 하자. mut 로 해 보면 막힌다.

rust
fn main() {
    let mut price = 12000;
    price = "12000 won";
    println!("{price}");
}
text
error[E0308]: mismatched types
 --> src/main.rs:3:13
  |
2 |     let mut price = 12000;
  |                     ----- expected due to this value
3 |     price = "12000 won";
  |             ^^^^^^^^^^^ expected integer, found `&str`
  1. 무엇 — 타입이 안 맞는다(mismatched types).
  2. 어디 — 3번째 줄의 "12000 won". 정수가 와야 하는데 문자열(&str)이 왔다. 2번째 줄의 12000 이 이 변수를 정수로 정했다(expected due to this value).
  3. 고치는 법 — help: 는 없다. 변수 하나는 처음 정해진 타입을 끝까지 지킨다.

mut 는 값을 바꾸게 해 줄 뿐, 타입을 바꾸게 해 주지는 않는다. 가림은 새 변수를 만드는 것이라 타입이 달라도 된다.

rust
fn main() {
    let price = 12000;
    println!("{price}");

    let price = "12000 won";
    println!("{price}");
}
text
   Compiling price v0.1.0 (~/projects/price)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/price`
12000
12000 won

03 블록 안에서 가리면 블록이 끝날 때 돌아온다

중괄호 { } 로 묶은 부분을 블록이라 한다. 블록 안에서 만든 변수는 블록이 끝나면 사라진다. 그래서 블록 안에서 가리면, 블록이 끝난 뒤에는 바깥 값이 다시 보인다.

rust
fn main() {
    let price = 12000;

    {
        let price = price * 2;
        println!("block: {price}");
    }

    println!("main: {price}");
}
text
   Compiling price v0.1.0 (~/projects/price)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/price`
block: 24000
main: 12000

블록 안의 price 는 24000 이었지만, 블록을 나온 뒤의 price 는 처음 그대로 12000 이다. 블록 안에서 새 변수를 만들었을 뿐, 바깥 변수는 건드리지 않았기 때문이다.

04 실습 — mut 와 가림 중 무엇을 쓸까

let mut price다시 let price (가림)
하는 일같은 변수의 값을 바꾼다같은 이름의 새 변수를 만든다
타입이 다른 값안 된다 (E0308)된다
바꾼 다음계속 바꿀 수 있다다시 못 바꾼다

정리하면, 값이 계속 바뀌는 카운터 같은 것은 mut, 한 번 손질하고 끝나는 값은 가림이 어울린다. 위의 할인 예제를 mut 로 바꿔 써 보고, 어느 쪽이 더 읽기 쉬운지 비교해 보자. 다음 편부터는 Rust 의 기본 타입을 하나씩 본다. 첫 번째는 정수다.