섀도잉이란
업다운게임 튜토리얼에서 보았듯이, 이전 변수와 같은 이름으로 새로운 변수를 선언할 수 있습니다.
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
guess가 두번 선언됨
이를 변수 가리기 (Shadowing)이라고 합니다.
두번째 변수가 첫번째 변수를 가린다는 뜻으로, 해당 변수 이름을 사용할 때 컴파일러가 두번째 변수를 인식한다는 의미입니다.
결과적으로 두번째 변수는 첫번째 변수를 가리고,
이 상태는 두번째 변수가 또 다른 새로운 변수에 의해 가려지거나 해당 범위(scope)가 끝날 때 까지 유지됩니다.
fn main() {
let x = 5;
let x = x + 1;
{
let x = x * 2;
println!("The value of x in the inner scope is: {x}");
}
println!("The value of x is: {x}");
}
맨 먼저 x를 값 5로 바인딩합니다.
그 다음, let x = 를 반복하여 새로운 변수를 선언하며 기존 값에 1을 더해 x를 6으로 만듭니다.
이후, 중괄호로 생성된 내부 스코프에서 세번째 let 선언은 또 다른 x를 선언하여 이전값에 2를 곱합니다.
여기서 let x의 x는 세번째 x이며, 우측의 표현식 x * 2의 x는 두번째 x (6)입니다. 따라서 세번째 x는 12가 됩니다.
내부 스코프 { }가 종료되었습니다. 세번째 x는 내부 스코프에서 정의되었으므로,
이 스코프가 끝나면 섀도잉이 종료되고 x는 다시 외부의 스코프, 두번째 스코프의 값 6이 됩니다.
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
Running `target/debug/variables`
The value of x in the inner scope is: 12
The value of x is: 6
섀도잉과 mut의 차이점
불변성을 유지하면서 값 변환
mut 키워드를 사용하지 않고 let을 반복해 새로운 변수를 생성함으로써 값을 변환할 수 있습니다.
이 과정에서 변수는 여전히 불변으로 유지됩니다.
mut를 사용할 경우, 변수 값이 재할당 가능해지지만 잘못된 재할당시 컴파일타임 오류를 놓치기 쉬울 수 있습니다.
타입 변경 가능
mut와 섀도잉의 가장 큰 차이점입닌다. let은 새로운 변수를 생성하는 것이므로, 같은 이름을 사용하면서도 타입 변경이 가능합니다.
예를들어 공백 문자를 저장한 후, 이를 개수로 변환하고자 한다면,
let spaces = " ";
let spaces = spaces.len();
위와 같이 작성해야 할것입니다.
첫번째 변수는 &str 타입이고, 두번째 변수는 숫자 타입(usize)입니다.
섀도잉을 사용하면, spaces_str와 spaces_num과 같은 다른 이름을 가진 두 변수를 굳이 선언할 필요가 없겠지요
spaces라는 하나의 변수명을 재사용할 수 있습니다.
그러나 mut을 이용한다면, 컴파일 시 오류가 발생합니다.
let mut spaces = " ";
spaces = spaces.len();
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
error[E0308]: mismatched types
--> src/main.rs:3:14
|
2 | let mut spaces = " ";
| ----- expected due to this value
3 | spaces = spaces.len();
| ^^^^^^^^^^^^ expected `&str`, found `usize`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `variables` (bin "variables") due to 1 previous error
expected `&str`, found `usize`
처음 spaces 선언 시 타입추론을 통해 spaces의 타입은 &str로 정해졌으며,
가변변수를 사용한다 하더라도 다른 타입의 값을 집어넣을 수는 없습니다.
퀴즈
A. 아래 프로그램의 컴파일 여부를 작성하세요. 만약 컴파일 가능하다면 실행결과를 작성하세요.
fn main() {
let mut x: u32 = 1;
{
let mut x = x;
x += 2;
}
println!("{x}");
}
B. 아래 프로그램의 컴파일 여부를 작성하세요. 만약 컴파일 가능하다면 실행결과를 작성하세요.
fn main() {
let mut x: u32 = 1;
x = "Hello world";
println!("{x}");
}
퀴즈의 정답과 해설
A. 컴파일됨, 1
let mut x: u32 = 1을 통해, 가변변수 x를 선언하고 값 1을 넣습니다. 이를 첫번째 x라 하겠습니다
내부스코프 { }로 진입합니다. 여기서 아직 x는 첫번째 x를 가리킵니다.
let mut x = x; 에서 새로운 x가 선언됩니다. 이를 두번째 x라 하겠습니다
우측의 표현식에서 x는 첫번째 x입니다. 첫번째 x의 값은 1 이므로
let mut x = 1;과 동일합니다
이제 두번째 x는 1이며, 첫번째 x를 섀도잉합니다. 값이 동일하더라도 다른 변수임을 인지해야합니다.
x+=2 를 보겠습니다. 이는 x = x + 2로 치환될 수 있습니다. 여기서 x는 두번째 x입니다
두번째 x는 가변변수입니다. 따라서 새로운 값을 바인딩할 수 있습니다.
두번째 x는 3이 됩니다. 첫번째 x는 여전히 1임에 유의합시다
내부스코프가 종료됩니다. 이후 내부스코프에서 선언된 변수들에게는 더이상 접근할 수 없습니다.
x를 출력합니다. 두번째 x는 내부스코프가 종료됨과 동시에 접근할 수 없게 되었으며, x는 첫번째 x를 가리키고 있습니다.
따라서 x값은 1입니다.
B. 컴파일되지 않음
x는 u32, 숫자타입으로 선언되었습니다.
그 아래에서 x에 &str를 바인딩하려 하네요, 섀도잉을 하지 않는 이상 불가능한 동작입니다.
따라서 타입오류로 컴파일되지 않습니다.
'Rust' 카테고리의 다른 글
RustBook - 상수 (Constants) (0) | 2024.12.02 |
---|---|
RustBook - 변수와 가변성 (Variables and Mutability) (0) | 2024.12.01 |
RustBook - 업다운게임 만들기 (Programming a Guessing Game) (0) | 2024.11.30 |