RustBook - 변수와 가변성 (Variables and Mutability)
2장에서 업다운 게임을 만들때, guess 변수를 생성하면서
Rust는 기본적으로 변수들이 "불변 (immutable)"이라고 언급한 바 있습니다.
이는 Rust가 제공하는 안전성과 쉬운 병렬처리를 활용하도록 유도하는 여러가지 특징 중 하나입니다.
그러나 우리는 guess 변수를 "가변 (mutable)" 변수로 선언하였습니다.
다른 언어를 사용하다 왔으면 왜 이렇게 불편하게 만들어놨는지 의문이 드실겁니다.
Rust가 왜 불변성을 권장하는지, 그리고 어떨 때 가변 변수를 선택해야 할지 살펴보겠습니다.
불변 변수 (Immutable Variable)
변수가 불변일때, 특정 값이 변수에 바인딩되면 그 값을 변경할 수 없습니다.
진짜로 그런지 살펴보겠습니다.
새로운 프로젝트를 만들고, main.rs의 코드를 아래와 같이 작성합니다.
fn main() {
let x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
cargo run으로 이 코드를 실행해보겠습니다.
결과는 아래와 같습니다
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| - first assignment to `x`
3 | println!("The value of x is: {x}");
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
|
help: consider making this binding mutable
|
2 | let mut x = 5;
| +++
For more information about this error, try `rustc --explain E0384`.
error: could not compile `variables` (bin "variables") due to 1 previous error
이 예제는 컴파일러가 프로그램 내의 오류를 찾아내는 방식을 보여줍니다.
컴파일오류는 짜증날 수 있으나, 실제로는 프로그램이 아직 완전하게 원하는 작업을 수행하지 못하고 있음을 의미할 뿐입니다.
이는 프로그래머의 실력과는 무관합니다. 숙련된 Rust 개발자들도 여전히 컴파일러 오류를 마주합니다.
오류 메세지를 살펴보겠습니다.
" cannot assign twice to immutable variable "
" 불변 변수에 값을 두번 할당할 수 없음"
그 아래에는 mut 키워드를 사용하여 가변변수를 만들라고 권장하고 있습니다
불변성이 중요한 이유
코드의 한 부분에서 특정 값이 절대로 변경되지 않을것이라는 가정 하에 동작해야한다고 가정해봅시다.
하지만 프로그래머의 실수로 해당 값이 변경되었다면 이는 런타임 과정에서 문제를 일으킬것입니다.
특히나 값이 조건적으로 변경되는 경우, 이런 문제는 디버깅하기 더욱 어려워질 수 있습니다.
Rust 컴파일러는 값이 변경되지 않겠다고 선언하면, 실제로 값이 변경되지 않음을 컴파일 과정에서 검사하고 이를 보장합니다.
이는 프로그래머가 직접 값을 추적하지 않아도 되도록 하며, 코드가 더 이해하기 쉬워집니다.
가변 변수 (Mutable Variable)
불변 변수만 이용하여 프로그래밍을 하기는 쉽지않아보입니다.
물론, 함수형 프로그래밍을 완벽하게 추구한다면 가변성을 최대한 배제하는 것이 맞으나,
코드 작성의 편리함을 위해 Rust는 가변변수를 지원합니다.
기본적으로 변수는 불변이지만, 변수 이름 앞에 mut 키워드를 추가하면 가변성을 부여할 수 있습니다.
이는 코드의 다른 부분이 이 변수의 값을 변경할 것임을 미래에 코드를 읽는사람들에게 전달하는 역할도 합니다.
fn main() {
let mut x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.30s
Running `target/debug/variables`
The value of x is: 5
The value of x is: 6
mut 키워드를 사용하여, 여타 다른 프로그래밍 언어에서 했던 것과 같이 변수에 값을 바인딩할 수 있습니다.
만약 mut 키워드를 사용하여 가변 변수를 선언하지만, 해당 값을 바꾸지 않으면 어떻게될까요?
변수 바인딩 부분을 지워보겠습니다.
fn main() {
let mut x = 5;
println!("The value of x is: {x}");
}
warning: variable does not need to be mutable
--> tester\src/main.rs:2:9
|
2 | let mut x = 5;
| ----^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
warning: `tester` (bin "tester") generated 1 warning (run `cargo fix --bin "tester"` to apply 1 suggestion)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.80s
Running `target\debug\tester.exe`
The value of x is: 5
코드는 작동하지만, 컴파일러가 warning을 표시해줍니다.
"variable does not need to be mutable"
"이 변수는 가변일 필요가 없음"
가변변수일 필요가 없으므로, mut을 없애라고 권장해줍니다.
결론
결국, 가변성을 사용할지 여부는 상황에 따라 달라집니다.
특정 상황에서 무엇이 가장 명확한지에 따라 프로그래머가 결정하면 됩니다.
불변 변수는 더 많은 안전성을 제공하고, 가변 변수는 더 많은 유연성을 제공합니다.
Rust는 기본적으로 불변성을 권장하지만, 필요한 경우 가변성을 명시적으로 허용하는 방식으로 설계되어 있습니다.
퀴즈
A. 변수 x가 불변(immutable)하다는것은 무엇을 의미하나요?
1. x에 대한 참조를 생성할 수 없습니다.
2. x는 값이 할당된 후 변경할 수 없습니다.
3. x는 불변 메모리 영역에 저장됩니다.
4. 정의된 후 x는 최대 한번만 변경될 수 있습니다.
B. let 뒤에 무엇을 작성해야 가변변수로 만들 수 있나요?
C. 아래 프로그램의 컴파일 여부를 작성하세요. 만약 컴파일 가능하다면 실행결과를 작성하세요.
fn main() {
let x = 1;
println!("{x}");
x += 1;
println!("{x}");
}
퀴즈의 정답 및 해설
A. 2
Immutable의 기본적인 정의를 물어봤네요. 값이 할당된 후 변경할 수 없다가 정의입니다. 정답은 2번입니다.
B. mut
let mut x = 1; 처럼 mut 키워드를 통해 가변변수를 만들 수 있습니다.
C. 컴파일되지 않음
let x를 통해 x가 불변 변수(immutable variable)임을 확인할 수 있습니다.
line 4에서 x+=1 을 통해 새로운 변수를 할당하려 했습니다. 여기서 컴파일러 오류가 발생됩니다.