[Rust] 변수와 가변성: 불변 변수, mut, 상수, 섀도잉

이 글은 The Rust Programming Language 3.1장 "Variables and Mutability"을 읽고 정리한 내용이에요. 예제도 이 장의 예제를 바탕으로 했어요.

Rust의 가장 기초인 변수와 가변성, 그리고 상수와 섀도잉을 정리해 볼게요.


변수는 기본적으로 바꿀 수 없어요 (Immutability)

Rust에서 let으로 선언한 변수는 기본적으로 불변(immutable) 이에요. 한 번 값을 정하면 나중에 바꿀 수 없다는 뜻이에요. 이렇게 만든 이유는 데이터의 안정성 때문이에요. 코드 한쪽은 값이 그대로라고 가정하는데 다른 쪽에서 값을 바꾸면 버그가 생기기 쉬워요.

예시를 볼게요. 이 코드는 컴파일되지 않아요.

Rust
fn main() {
    let x = 5;
    println!("x의 값: {x}");
    x = 6; // 여기서 에러 발생!
    println!("x의 값: {x}");
}

컴파일하면 error[E0384]: cannot assign twice to immutable variable x``(불변 변수 x에 두 번 할당할 수 없다는 에러)가 나요.


값을 바꿔야 할 때: mut 키워드

프로그램을 만들다 보면 값이 바뀌어야 하는 상황이 생겨요. 그럴 때는 변수 이름 앞에 mut 키워드를 붙이면 돼요. "이 변수는 앞으로 값이 바뀔 수 있다"고 미리 선언하는 거예요.

Rust
fn main() {
    let mut x = 5;
    println!("처음 x의 값: {x}");
    x = 6; // 이제 가능해요!
    println!("바뀐 x의 값: {x}");
}

mut를 쓰면 나중에 코드를 읽는 사람도 "x는 중간에 값이 바뀌는 변수구나"라고 바로 알 수 있어요.


바뀌지 않는 값: 상수 (Constants)

변수와 비슷해 보이지만 더 엄격한 게 상수(constants) 예요. 상수는 const 키워드로 선언해요.

변수와 다른 점은 세 가지예요.

  1. mut를 쓸 수 없어요. 항상 불변이에요.
  2. 타입을 반드시 적어야 해요. (u32 같은 타입은 다음 장에서 다뤄요.)
  3. 실행 중에 계산되는 값은 넣을 수 없고, 컴파일 시점에 계산할 수 있는 값만 넣을 수 있어요.
Rust
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

이름은 보통 전부 대문자로 쓰고 단어 사이를 밑줄(_)로 이어요. 게임의 최대 점수나 빛의 속도처럼 프로그램 어디서든 바뀌지 않는 값을 정할 때 써요.


같은 이름을 다시 쓰는 섀도잉 (Shadowing)

Rust에는 섀도잉(shadowing) 이라는 개념이 있어요. 이미 쓴 변수 이름을 let으로 다시 선언하는 거예요. 그러면 뒤에 선언한 변수가 앞의 변수를 가려요.

Rust
fn main() {
    let x = 5;
    let x = x + 1; // 5 + 1 = 6

    {
        let x = x * 2; // 6 * 2 = 12
        println!("안쪽 중괄호에서의 x 값: {x}");
    }

    println!("바깥쪽 x 값: {x}"); // 다시 6이 출력돼요
}

mut와 섀도잉은 뭐가 다를까요?

  • 타입을 바꿀 수 있어요: 섀도잉은 이름은 같지만 타입이 다른 새 변수를 만들 수 있어요. 예를 들어 공백 문자열 " "을 받아서 그 길이인 숫자 3으로 바꿔 같은 이름에 다시 담을 수 있어요. mut로는 타입을 바꿀 수 없어요.
  • 불변성이 유지돼요: 섀도잉은 새 변수를 만드는 거라서, 값을 바꾼 뒤에도 그 변수는 다시 불변이에요.

요약

개념설명
ImmutabilityRust 변수는 기본적으로 불변이에요. 코드의 안정성을 높여 줘요.
mut변수 이름 앞에 붙여서 값을 바꿀 수 있게 해요.
Constantsconst로 선언하고, 바뀌지 않는 고정값에 써요. 타입을 반드시 적어야 해요.
Shadowinglet으로 같은 이름을 다시 선언해요. 타입을 바꿀 수 있어요.