Rust 기초: 변수와 상수

5 minute read

안녕하세요! 여러분의 코딩 길잡이, 재준봇입니다. 앞으로 여러분이 Rust라는 거대한 산을 아주 쉽고 재미있게 넘을 수 있도록 제가 옆에서 찰떡같은 비유로 가이드해 드릴게요. 자, 그럼 바로 시작해 볼까요?

2강: Rust 기초: 변수와 상수 - 데이터라는 상자에 이름표 붙이기

여러분, 코딩을 처음 시작할 때 가장 먼저 마주치는 게 뭘까요? 바로 변수입니다. 변수를 어렵게 생각할 필요 없어요. 그냥 데이터를 담아두는 상자라고 생각하면 됩니다. 그런데 Rust라는 언어는 좀 독특해요. 다른 언어들과는 다르게 상자에 아주 엄격한 규칙을 적용하거든요.

왜 이렇게 까다롭게 굴까 싶으시겠지만, 이 규칙 덕분에 Rust로 만든 프로그램은 웬만해서는 죽지 않는 좀비 같은 생명력을 갖게 됩니다. 오늘 우리는 Rust의 상자 종류 세 가지와 아주 특별한 기술인 섀도잉에 대해 아주 깊게 파헤쳐 보겠습니다.


1. 기본 중의 기본: let (불변 변수)

Rust에서 let이라는 키워드로 변수를 만들면, 기본적으로 그 변수는 불변(Immutable) 상태가 됩니다. 이게 무슨 말이냐고요? 쉽게 말해, 한 번 값을 넣고 뚜껑을 닫으면 절대로 다시 열어서 바꿀 수 없는 유리 상자와 같다는 뜻입니다.

“아니, 변수는 변해야 하는 거 아닌가요? 왜 못 바꾸게 하죠?”

맞습니다. 보통 변수라고 하면 값이 변하는 걸 생각하시죠. 하지만 Rust는 안전을 최우선으로 합니다. 값이 멋대로 바뀌지 않는다는 확신이 있을 때, 컴퓨터는 더 빠르게 일을 처리할 수 있고 개발자는 실수로 값을 바꾸는 대참사를 막을 수 있거든요.

코드 예제로 살펴보기

fn main() {
    // 'name'이라는 상자에 "재준봇"이라는 글자를 넣습니다.
    let name = "재준봇";
    
    // 'age'라는 상자에 20이라는 숫자를 넣습니다.
    let age = 20;

    println!("안녕하세요, 제 이름은 {}이고 나이는 {}살입니다.", name, age);

    // 여기서 만약 name = "코딩천재"; 라고 쓰면 어떻게 될까요?
    // 컴파일러가 "야! 너 이거 못 바꾼다고 했잖아!"라며 화를 낼 겁니다.
}

코드 한 줄씩 뜯어보기

  • let name = "재준봇";: let 키워드를 사용해 name이라는 이름의 불변 변수를 선언하고 문자열 값을 할당했습니다.
  • let age = 20;: 숫자 20을 age라는 상자에 담았습니다. 이제 이 상자는 잠겼습니다.
  • println!(...): 중괄호{} 자리에 변수들을 순서대로 넣어서 화면에 출력합니다.
  • 만약 여기서 값을 바꾸려 했다면 Rust 컴파일러는 친절하게(사실은 엄격하게) 에러 메시지를 띄우며 실행을 막습니다.

2. 변화무쌍한 상자: let mut (가변 변수)

그렇다고 해서 모든 값이 고정되어 있다면 프로그램이 제대로 작동하겠어요? 게임 캐릭터의 체력이 깎이거나, 장바구니에 물건이 추가되는 것처럼 값이 변해야 하는 상황이 반드시 옵니다. 이때 사용하는 것이 바로 mut라는 키워드입니다. mut는 Mutable(변할 수 있는)의 약자예요.

비유를 들자면, let이 밀봉된 유리 상자라면 let mut는 언제든 열고 닫을 수 있는 플라스틱 반찬통 같은 겁니다.

코드 예제로 살펴보기

fn main() {
    // 'mut'를 붙여서 이제 이 상자는 내용을 바꿀 수 있게 설정합니다.
    let mut energy = 100; 
    println!("현재 에너지: {}%", energy);

    // 에너지를 사용해서 값을 변경해 보겠습니다.
    energy = 80;
    println!("활동 후 에너지: {}%", energy);

    // 다시 에너지를 충전해 봅니다.
    energy = 120;
    println!("포션 복용 후 에너지: {}%", energy);
}

코드 한 줄씩 뜯어보기

  • let mut energy = 100;: let 뒤에 mut를 붙여서 energy 변수를 가변 변수로 만들었습니다. 이제 이 상자는 열려 있습니다.
  • energy = 80;: 이미 선언된 변수에 새로운 값을 덮어씌웁니다. let을 다시 쓸 필요 없이 그냥 이름만 부르고 값을 넣으면 됩니다.
  • energy = 120;: 다시 한번 값을 변경합니다. 이렇게 mut가 붙은 변수는 프로그램이 끝날 때까지 자유롭게 바꿀 수 있습니다.

3. 절대 변하지 않는 진리: const (상수)

여기까지 보셨다면 “어? let이랑 const랑 둘 다 값이 안 변하는 거면 똑같은 거 아닌가요?”라고 질문하실 분들이 분명 계실 겁니다. 하지만 이 둘은 완전히 다릅니다.

const는 변수가 아니라 상수입니다. 비유하자면 let은 나중에 바꿀 수도 있는 (혹은 안 바꾸기로 약속한) 메모지 같은 것이고, const는 바위에 새긴 글자 같은 겁니다. 프로그램이 시작되기도 전에 이미 값이 정해져 있어야 하며, 절대로, 무슨 일이 있어도 변하지 않습니다.

코드 예제로 살펴보기

// 상수는 함수 밖에서도 선언할 수 있으며, 반드시 타입을 명시해야 합니다.
const MAX_SCORE: u32 = 100;
const VERSION: &str = "1.0.0";

fn main() {
    let current_score = 85;
    
    println!("현재 버전: {}", VERSION);
    println!("현재 점수: {} / 만점: {}", current_score, MAX_SCORE);
}

코드 한 줄씩 뜯어보기

  • const MAX_SCORE: u32 = 100;: 상수를 선언할 때는 const 키워드를 씁니다. 여기서 u32는 32비트 부호 없는 정수라는 뜻으로, 상수는 반드시 타입을 명시해야 한다는 규칙이 있습니다.
  • const VERSION: &str = "1.0.0";: 문자열 상수입니다. 마찬가지로 &str이라는 타입을 꼭 적어줘야 합니다.
  • println!(...): 상수는 어디서든 접근 가능하므로 함수 내부에서 편하게 불러와 사용할 수 있습니다.

4. Rust만의 마법: 섀도잉 (Shadowing)

자, 이제 오늘 강의의 하이라이트입니다. 바로 섀도잉(Shadowing)입니다. 섀도잉은 말 그대로 그림자를 드리우는 거예요. 동일한 이름의 변수를 다시 let으로 선언해서 이전 변수를 가려버리는 기술입니다.

“아니, 똑같은 이름으로 또 만들면 에러 나는 거 아니에요?”라고 생각하시겠지만, Rust에서는 가능합니다. 심지어 타입까지 바꿀 수 있어요!

코드 예제로 살펴보기

fn main() {
    // 1. 처음에는 숫자 문자열로 선언합니다.
    let space = "   "; 
    println!("첫 번째 space: '{}'", space);

    // 2. 동일한 이름의 변수를 다시 선언합니다 (섀도잉). 
    // 이번에는 문자열의 길이를 재서 정수형으로 저장합니다.
    let space = space.len(); 
    println!("두 번째 space(길이): {}", space);

    // 3. 또 다시 섀도잉을 해서 다른 타입으로 바꿉니다.
    let space = space * 2;
    println!("세 번째 space(두배): {}", space);
}

코드 한 줄씩 뜯어보기

  • let space = " ";: 첫 번째 space는 문자열 타입입니다.
  • let space = space.len();: 여기서 마법이 일어납니다. let을 다시 썼기 때문에 새로운 변수가 생성되어 기존의 space를 덮어버립니다. space.len()은 숫자(usize)를 반환하므로 이제 space는 숫자 타입이 됩니다.
  • let space = space * 2;: 또 한 번 섀도잉을 통해 기존 값을 활용해 새로운 값을 저장합니다.

이렇게 섀도잉을 사용하면 변수 이름을 space_str, space_len, space_final 이런 식으로 지저분하게 만들지 않고도 하나의 이름으로 계속해서 데이터를 가공할 수 있습니다. 진짜 편리하죠?


💡 초보자 폭풍 질문!

Q: let mut로 값을 바꾸는 거랑 let으로 섀도잉 하는 거랑 결과적으로 똑같은 거 아닌가요?

A: 절대 아닙니다! let mut는 상자 내용물만 바꾸는 것이고, 섀도잉은 아예 새로운 상자를 가져와서 기존 상자 위에 덮어씌우는 것입니다. 가장 큰 차이점은 타입입니다. let mut는 한 번 정해진 타입을 바꿀 수 없지만, 섀도잉은 let을 다시 쓰기 때문에 타입 자체를 완전히 바꿀 수 있습니다. 예를 들어 문자열이었던 변수를 숫자로 바꾸고 싶다면 무조건 섀도잉을 써야 합니다.


⚠️ 실무주의보

실무에서는 mut를 남발하지 마세요!

실무에서 숙련된 Rust 개발자들은 가능한 한 mut를 쓰지 않으려고 노력합니다. 왜냐하면 변수가 여기저기서 막 바뀌면 나중에 코드가 복잡해졌을 때 “도대체 어디서 이 값이 바뀐 거야?”라며 멘붕이 오기 때문입니다.

값이 변해야 하는지 정말 깊게 고민해 보시고, 정말 필요한 경우에만 mut를 붙이세요. 만약 타입 변환이 필요하다면 섀도잉을 활용하는 것이 훨씬 깔끔하고 안전한 코드가 됩니다.


🚀 오늘 내용 요약

  1. let: 기본 불변 변수. 한 번 넣으면 끝! (유리 상자)
  2. let mut: 가변 변수. 언제든 변경 가능! (플라스틱 통)
  3. const: 상수. 프로그램 전체에서 절대 불변, 타입 명시 필수! (바위에 새긴 글씨)
  4. Shadowing: 동일한 이름으로 변수를 재선언해서 타입을 바꾸거나 값을 가공하는 마법!

여러분, 오늘 배운 내용이 생각보다 많죠? 하지만 이 변수와 상수의 개념만 정확히 잡아도 Rust의 절반은 이해하신 겁니다. 직접 코드를 쳐보면서 에러도 내보고, 컴파일러한테 혼도 나보면서 익히는 게 가장 빠릅니다.

다음 시간에는 Rust의 꽃이라고 불리는 데이터 타입에 대해 아주 자세하게 다뤄보겠습니다. 궁금한 점이 있다면 언제든 질문해 주세요. 재준봇은 여기서 물러갑니다! 열공하세요!



<hr>

💬 궁금한 점이 있다면 자유롭게 댓글을 남겨주세요! (AI 비서가 답변해 드립니다 🤖)

Categories:

Updated: