보편적인 프로그래밍 개념 - 변수와 상수
개발 환경
이 문서에서 진행한 필자의 개발 환경은 다음과 같다.
- desktop: macbook pro 13 2020
- cpu: Intel Core i7 4core
- memory: 32GB
- rustup v1.24.3
- cargo v1.58.0
이 문서는 여러분이 cargo가 설치되어 있다고 가정한다. 만약 cargo를 설치하지 않았다면, 이 문서를 참고하여 설치 및 설정을 진행하길 바란다.
cargo
설치가 되었다면 이번 장을 위한 프로젝트를 생성한다.
# 프로젝트 생성
$ cargo new --bin variables
# 프로젝트 디렉토리로 이동
$ cd varialbes
let
let
은 rust
에서 변수를 선언하기 위한 키워드이다. 변수를 선언하려면 이런 형태로 선언해야 한다.
let 변수_이름: 타입 = 값;
예를 들어, 정수형 값 5를 갖는 변수 num
을 선언하고 싶다면 다음과 같이 선언할 수 있다.
let num: u32 = 5;
이 때 u32
는 정수형 타입 중 하나로 부호가 없는 32bit 정수형 타입이다. 이는 추후 진행할 "데이터 타입"에서 자세히 다룰 것이다. 이 문서에서는 정수형 타입 선언을 위해 쓰였다 정도로만 이해하자.
위 변수 선언은 이렇게 줄여 쓸 수도 있다.
let num = 5;
이제 본격적으로 프로그램을 만들어보자. main.rs
를 다음 내용으로 수정한다.
variables/src/main.rs
fn main() {
let num = 5;
println!("num: {}", 5)
}
이후 cargo run
명령어를 이용해서 프로그램을 실행시켜보자.
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.28s
Running `target/debug/variables`
num: 5
정수 5를 값으로 갖는 num
이란 변수를 선언하고 출력하는 매우 간단한 프로그램이다. 보편적으로 변수라하면 "변하는 수"이다. 한 번 이제 main.rs
에서 num
의 값을 변경해보자.
variables/src/main.rs
fn main() {
let num = 5;
println!("num: {}", num);
num = 6;
println!("num: {}", num);
}
위 프로그램은 어떻게 동작할까? 우리의 예상대로 변수의 값이 변경될까? 한 번 프로그램을 실행시켜보자.
let mut
다음은 위에서 만든 프로그램을 cargo run
을 통해 실행한 결과이다.
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
error[E0384]: cannot assign twice to immutable variable `num`
--> src/main.rs:5:5
|
2 | let num = 5;
| ---
| |
| first assignment to `num`
| help: consider making this binding mutable: `mut num`
...
5 | num = 6;
| ^^^^^^^ cannot assign twice to immutable variable
For more information about this error, try `rustc --explain E0384`.
실행이 되지 않는다. 왜 그런지는 컴파일러가 잘 설명해준다. 이유는 기본적으로 rust
의 변수는 불변성을 가지고 있기 때문이다. 왜 변수인데 불변성을 가져야 할까? rust
는 다른 프로그래밍 언어보다 안정성을 더 생각하고 설계된 언어이기 때문이다. 이는 다른 문서에서 더 자세히 다루도록 하자. 지금은 안전한 프로그래밍을 위해 기본적으로는 변수는 변하지 않는다 정도로만 이해하자.
그렇다면, 위 프로그램을 동작시키기 위해서는 어떻게 해야할까? 역시 컴파일러가 친절하게 알려주고 있다.
...
2 | let num = 5;
| ---
| |
| first assignment to `num`
| help: consider making this binding mutable: `mut num`
...
변수를 프로그램 실행 시 변하게 하고 싶다면 let mut
으로 변수를 선언하면 된다. main.rs
를 다음과 같이 수정한다.
variables/src/main.rs
fn main() {
let mut num = 5;
println!("num: {}", num);
num = 6;
println!("num: {}", num);
}
이제 다시 프로그램을 실행시켜보자.
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.24s
Running `target/debug/variables`
num: 5
num: 6
const
보편적으로 프로그래밍 언어에서 "변수"와 "상수"란 개념은 쌍이다. 변수는 변할 수 있는 값이라면, 상수는 절대 변하지 않는 값이다. rust
에서도 상수를 위한 키워드가 있다. 상수를 선언하려면 다음과 같이 할 수 있다.
const 상수_이름: 상수 타입 = 값;
정수 5를 값는 상수 NUM
을 선언하고 싶으면 다음과 같이 선언할 수 있다. (상수는 대문자로 이름 짓는 것이 관례이다.)
const NUM: u32 = 5;
역시 변수처럼 축약할 수 있다.
const NUM = 5;
이번엔 main.rs
를 다음과 같이 변경해보자.
variables/src/main.rs
fn main() {
const NUM: u32 = 5;
println!("NUM: {}", NUM);
NUM = 6;
println!("NUM: {}", NUM);
}
이제 프로그램을 실행시켜보자. 잘 될까?
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
error[E0070]: invalid left-hand side of assignment
--> src/main.rs:5:9
|
5 | NUM = 6;
| --- ^
| |
| cannot assign to this expression
For more information about this error, try `rustc --explain E0070`.
error: could not compile `variables` due to previous error
당연히 안된다. 상수는 절대 변할 수 없는 값이라 했다. 따라서 값을 바꾸면 에러가 뜬다. 조금 특이한 점은 let
만 썼을 때와는 에러 출력문이 다르다는 것이다.
let
만 썼을 때는 consider making this binding mutable: `mut num`
문구를 출력하면서 어떻게 하면 에러를 고칠 수 있는지 알려줬다면 const
는 이 표현식은 사용할 수 없다는 에러가 뜬다.
이 에러를 고치려면 상수 값을 재 할당하는 부분을 삭제하면 된다. 다음과 같이 수정하자.
variables/src/main.rs
fn main() {
const NUM: u32 = 5;
println!("NUM: {}", NUM);
}
이제 프로그램을 실행시켜보자.
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.24s
Running `target/debug/variables`
NUM: 5
let shaddowing
이제 shaddowing
이란 개념을 알아보자. let
은 기본적으로 불변이라고 했다. 여기서 let mut
으로 바꾸면 가변성을 갖는다. rust
에서 변수를 바꾸는 방법은 1가지가 더 있는데 바로 shaddowing
이란 기법을 이용하는 것이다. shaddowing
을 사용하면 불변성을 유지하면서 변수를 바꿀 수가 있다.
main.rs
를 다음과 같이 수정해보자.
variables/src/main.rs
fn main() {
let spaces = " ";
spaces = spaces.len();
println!("The value of spaces is: {}", spaces);
}
위 프로그램은 " "(공백 4칸)
문자열 값을 갖는 spaces
변수를 선언한다. 그 이후 문자열 타입의 len
메소드를 호출하여 문자열 길이를 다시 spaces
에 할당하고 출력하는 프로그램이다. 위 프로그램은 과연 잘 동작할까?
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
error[E0308]: mismatched types
--> src/main.rs:3:14
|
2 | let 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` due to previous error
당연히 잘 동작하지 않는다. 기본적으로 rust
에서 변수는 불변하다. 때문에 값을 변경하기 때문에 에러가 발생한다. 그럼 let mut
으로 변경해보면 어떨까?
variables/src/main.rs
fn main() {
let mut spaces = " ";
spaces = spaces.len();
println!("The value of spaces is: {}", spaces);
}
잘 동작할 것 같은가? 프로그램을 실행시켜보자.
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/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` due to previous error
같은 컴파일 오류를 나타내고 있다. let mut
을 통해 변수의 값을 변경할 수 있을텐데 왜 안되는 것일까? 일반적으로 프로그래밍에서는 변수를 한 번 선언하면 그 타입은 절대 바뀌지 않는다. 근데 위 프로그램은 " "
값을 갖는 문자열 변수 spaces
를 선언해놓고 spaces.len()
을 통해 문자열 길이를 값으로 갖는 정수형 값을 변수에 넣으려고 하기 때문에 이런 오류가 발생하는 것이다.
이 때 shaddowing
기법을 이용하면 이를 해결할 수 있다. main.rs
를 다시 다음과 같이 수정하자.
variables/src/main.rs
fn main() {
let spaces = " ";
let spaces = spaces.len(); # 위 문자열 타입의 spaces를 이용한다. 여기서부터 spaces는 문자열 길이를 값으로 갖는 정수형 변수이다.
println!("The value of spaces is: {}", spaces);
}
프로그래밍 경험이 있다면 해괴 망측한 코드가 아닐 수 없다. 같은 이름을 갖는 변수를 다시 선언하다니... 하지만 rust
에서는 같은 이름을 가지는 변수를 사용한다는 조건 하에서 같은 이름을 갖는 변수를 다시 선언할 수 있다. 이 때 타입도 변경할 수 있는 것이다. 이게 바로 shaddowing
기법이다.
이제 프로그램을 다시 한 번 실행해보자.
$ cargo run
Compiling variables v0.1.0 (/Users/gurumee/Workspace/today-i-learned/getting-started-rust-programming/ch03/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/variables`
The value of spaces is: 4
문자열 길이 4가 출력되는 것을 확인할 수 있다.