ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 보편적인 프로그래밍 개념 - 변수와 상수
    24년 11월 이전/Rust 2022. 2. 26. 19:46
    반응형

    개발 환경

    이 문서에서 진행한 필자의 개발 환경은 다음과 같다.

    • 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

    letrust에서 변수를 선언하기 위한 키워드이다. 변수를 선언하려면 이런 형태로 선언해야 한다.

    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가 출력되는 것을 확인할 수 있다. 

    728x90

    '레거시 > Rust' 카테고리의 다른 글

    보편적인 프로그래밍 개념 - 데이터 타입  (0) 2022.03.06
    cargo 맛보기  (0) 2022.02.20
    rust 시작하기  (0) 2022.02.19
Designed by Tistory.