hyunsu blog

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

Rust 변수 — let 은 바꿀 수 없고, 바꿀 것만 mut 를 붙인다

목차 · 5
  1. 01let 으로 만든 변수는 바꿀 수 없다
  2. 02바꿀 변수에만 mut 를 붙인다
  3. 03절대 안 바뀌는 값은 const
  4. 04실습 — 오류를 먼저 예상해 보기
  5. 05자주 묻는 질문

Rust 에서 let 으로 만든 변수는 값을 바꿀 수 없다. 다시 대입하면 E0384 오류로 컴파일이 멈춘다. 값을 바꿀 변수에만 mut 를 붙이고, 프로그램 내내 그대로인 값은 const 로 둔다.

01 let 으로 만든 변수는 바꿀 수 없다

let 이름 = 값; 이 변수를 만드는 문장이다. println! 의 따옴표 안에 {이름} 을 쓰면 그 자리에 변수의 값이 찍힌다. 카운터를 하나 올리는 코드를 다른 언어 습관대로 쓰면 이렇게 된다.

rust
fn main() {
    let count = 0;
    println!("count = {count}");
    count = count + 1;
    println!("count = {count}");
}
text
   Compiling counter v0.1.0 (~/projects/counter)
error[E0384]: cannot assign twice to immutable variable `count`
 --> src/main.rs:4:5
  |
2 |     let count = 0;
  |         ----- first assignment to `count`
3 |     println!("count = {count}");
4 |     count = count + 1;
  |     ^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
  |
help: consider making this binding mutable
  |
2 |     let mut count = 0;
  |         +++

For more information about this error, try `rustc --explain E0384`.
error: could not compile `counter` (bin "counter") due to 1 previous error

2편에서 익힌 세 군데로 읽는다.

  1. 무엇 — 바꿀 수 없는(immutable) 변수 count 에 두 번 대입했다.
  2. 어디 — 4번째 줄이다. 처음 값을 넣은 2번째 줄도 함께 짚어 준다.
  3. 고치는 법 — let 뒤에 mut 를 넣으라고 한다.

02 바꿀 변수에만 mut 를 붙인다

시키는 대로 mut 를 붙이면 컴파일되고 값이 바뀐다.

rust
fn main() {
    let mut count = 0;
    println!("count = {count}");
    count = count + 1;
    println!("count = {count}");
}
text
   Compiling counter v0.1.0 (~/projects/counter)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
     Running `target/debug/counter`
count = 0
count = 1

기본이 "못 바꿈" 인 것은 읽기 쉬워서다. mut 가 없는 변수는 끝까지 처음 값 그대로라고 컴파일러가 보장한다. 코드를 읽다가 이 값이 어디서 바뀌었는지 찾아다닐 일이 없다. TypeScript 에서 let 보다 const 를 먼저 쓰는 습관과 비슷하다.

반대로 바꾸지도 않을 변수에 mut 를 붙이면 경고가 나온다.

rust
fn main() {
    let mut name = "Ferris";
    println!("Hello, {name}!");
}
text
   Compiling greeting v0.1.0 (~/projects/greeting)
warning: variable does not need to be mutable
 --> src/main.rs:2:9
  |
2 |     let mut name = "Ferris";
  |         ----^^^^
  |         |
  |         help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default

warning: `greeting` (bin "greeting") generated 1 warning (run `cargo fix --bin "greeting" -p greeting` to apply 1 suggestion)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s
     Running `target/debug/greeting`
Hello, Ferris!

warning 은 error 와 달리 컴파일을 막지 않는다. 그래서 마지막 줄에 Hello, Ferris! 가 찍혔다. 그래도 help: remove this mut 대로 지우는 편이 좋다. mut 는 "이 값은 바뀐다" 는 표시라서, 안 바뀌는 변수에 붙어 있으면 읽는 사람을 속인다.

03 절대 안 바뀌는 값은 const

최대 시도 횟수처럼 프로그램 내내 그대로인 값은 상수 const 로 둔다.

rust
const MAX_TRIES: u32 = 3;

fn main() {
    let mut tries = 1;
    println!("{tries}/{MAX_TRIES}");
    tries = tries + 1;
    println!("{tries}/{MAX_TRIES}");
}
text
   Compiling login v0.1.0 (~/projects/login)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/login`
1/3
2/3

const 에는 규칙이 셋 있다.

  • 타입을 꼭 적는다. : u32 가 타입 표기인데, 타입은 5편부터 하나씩 다룬다.
  • 이름은 대문자와 밑줄로 쓴다(MAX_TRIES).
  • 함수 밖에도 둘 수 있다. 위처럼 맨 위에 두면 파일 어디서나 쓴다.

04 실습 — 오류를 먼저 예상해 보기

아래 코드를 돌리기 전에, 어느 줄에서 무슨 오류가 날지 먼저 짐작해 보자.

rust
fn main() {
    let score = 80;
    score = 90;
    println!("{score}");
}

짐작했으면 돌려 본다.

text
error[E0384]: cannot assign twice to immutable variable `score`
 --> src/main.rs:3:5
  |
2 |     let score = 80;
  |         ----- first assignment to `score`
3 |     score = 90;
  |     ^^^^^^^^^^ cannot assign twice to immutable variable
  |
help: consider making this binding mutable
  |
2 |     let mut score = 80;
  |         +++

score 에 mut 가 없으니 3번째 줄에서 이 편 처음과 같은 E0384 가 났다. let mut score = 80; 으로 고치면 90 이 찍힌다. 다음 편에서는 mut 없이 같은 이름을 다시 쓰는 방법, 가림(shadowing)을 다룬다.

05 자주 묻는 질문

const 와 mut 없는 let 은 무엇이 다른가?

둘 다 못 바꾸지만, const 는 타입을 꼭 적고 컴파일할 때 정해지는 값만 담는다. let 은 실행 중에 계산한 값도 담을 수 있다.