[02. 프로그래밍 개념 익히기] - 제어문

Kurt·2023년 9월 7일
0

[Rust Language]

목록 보기
7/24
post-thumbnail

개요

다른 프로그래밍 언어가 대부분 가진 개념이 Rust에서 어떻게 다루어지는지 확인
그 중 제어문에 대한 이야기


if 표현식

실행 흐름을 제어할 수 있는 가장 보편적인 작성 방식은 if 표현식과 반복문이다.

기본적인 if 표현식

if 표현식은 우리가 조건에 따라 분기할 수 있게 해준다.
if를 한국어로 만약이라는 뜻과 같이 "만약 조건이 충족하면, 다음 코드를 실행하라"와 같은 실행 흐름을 제어할 수 있게 된다.
다음은 예시 코드이다.

fn main() {
    let number = 3;

    if number < 5 {
        println!("condition was true");
    } else {
        println!("condition was false");
    }
}

위처럼 if 표현식은 if라는 키워드로 시작하고 조건이 나온다.
위 코드의 결과는 다음과 같다.

$ cargo run
   Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
     Running `target/debug/branches`
condition was true

다음 코드는 타입에 대한 주의점을 알려준다.

fn main() {
    let number = 3;

    if number {
        println!("number was three");
    }
}

위 코드를 실행하면 아래와 같은 오류를 확인할 수 있다.

error[E0308]: mismatched types
 --> src/main.rs:4:8
  |
4 |     if number {
  |        ^^^^^^ expected bool, found integral variable
  |
  = note: expected type `bool`
             found type `{integer}`

위 에러는 Rust가 bool 형식을 기대하였으나 정수형이 왔다는 내용이고 Rust는 Ruby나 JS와 같이 자동으로 변환해주지 않는다.
만약 정수형으로 조건을 하고 싶은 경우에는 아래와 같이 작업이 가능하다.

fn main() {
    let number = 3;

    if number != 0 {
        println!("number was something other than zero");
    }
}

else if(다수 조건)

이번에는 ifelse 사이에 다수의 조건을 입력하기 위해서 else if 식을 사용해보려 한다.

fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}

위 스크립트는 분기할 수 있는 4가지의 조건이 존재하고 아래와 같은 결과가 나타날 것이다.

$ cargo run
   Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
     Running `target/debug/branches`
number is divisible by 3

위 스크립트에서 봐야할 중요한 사항으로 6이라는 값이 2로 나누어 떨어짐에도 불구하고, number is divisible by 2 라는 값이 출력되지 않는다는 점이다.
이렇게 되는 이유는 Rust가 첫 번째로 조건이 참이 되는 블록만 찾아 실행하고, 만약 찾게 된다면 나머지는 검색하지 않기 때문이다.

let 구문에서 if문 사용

위에서 보면 if 표현식이라고 말하는 것 처럼 if가 표현식이기 때문에 이를 let 구문의 우측에 사용할 수 있다.
다음은 예시이다.

fn main() {
    let condition = true;
    let number = if condition {
        5
    } else {
        6
    };

    println!("The value of number is: {}", number);
}

위 코드에서 변수 number에는 if 표현식에서 산출된 값이 bound 된다.
다음은 결과이다.

$ cargo run
   Compiling branches v0.1.0 (file:///projects/branches)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
     Running `target/debug/branches`
The value of number is: 5

여기서 주의해야 할 점은 if 표현식의 갈래 부분 즉 if 부분과 else 부분식의 각 갈래의 결과는 반드시 같은 타입이여야 한다.
예제로 다음의 코드를 확인해보자.

fn main() {
    let condition = true;

    let number = if condition {
        5
    } else {
        "six"
    };

    println!("The value of number is: {}", number);
}

위 코드에서는 조건이 참일경우 정수형, 참이 아닌 경우 문자형을 표현하는데 이렇게 다른 타입을 결과로 출력할 경우 아래와 같은 오류를 확인할 수 있다.

error[E0308]: if and else have incompatible types
 --> src/main.rs:4:18
  |
4 |       let number = if condition {
  |  __________________^
5 | |         5
6 | |     } else {
7 | |         "six"
8 | |     };
  | |_____^ expected integral variable, found reference
  |
  = note: expected type `{integer}`
             found type `&str`

반복문과 반복

코드 블록을 한 번 이상 수행하는 것은 자주 사용된다. 반복되는 작업을 위해, Rust는 3가지를 지원한다.(loop, while, for)

loop 키워드

loop 키워드는 Rust에게 그만두라고 명시하기 전까지 코드 블럭을 반복적으로 수행한다.
예시는 다음과 같다.

fn main() {
    loop {
        println!("again!");
    }
}

위 코드를 실행하면 강제로 정지하기 전까지 again! 이라는 문자열이 반복 출력하게 된다.
ctrl-C 키를 통해서 무한 루프를 탈출할 수 있다.

$ cargo run
   Compiling loops v0.1.0 (file:///projects/loops)
     Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!

또한 break를 사용하여 탈출할 수 있다.

while 키워드

반복문에서 조건이 참이 아니게 된 경우에 break를 호출하여 반복을 정지시킨다.
이런 패턴의 반복문을 구현하면 loop, if, else, break를 혼합해서 사용해야 한다.
하지만 위와 같은 동일한 구조체가 존재하는데 이것이 바로 while 키워드이다.
다음 예시는 while 키워드의 예시이다.

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{}!", number);

        number = number - 1;
    }

    println!("LIFTOFF!!!");
}

위 코드는 조건이 true인 동안 코드가 실행되고 그렇지 않으면 루프에서 벗어나게 된다.

for 키워드

코드를 작성하다 보면 다음과 같은 코드가 필요할 때가 있다.

fn main() {
    let a = [10, 20, 30, 40, 50];
    let mut index = 0;

    while index < 5 {
        println!("the value is: {}", a[index]);

        index = index + 1;
    }
}

위 코드에서 배열의 요소에 걸쳐서 카운트를 증가한다. index는 0부터 시작하고, 배열의 마지막 즉 5번째인 50 까지 반복된다. 이 코드를 수행하면 배열의 모든 요소가 출력되게 한다.

$ cargo run
   Compiling loops v0.1.0 (file:///projects/loops)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
     Running `target/debug/loops`
the value is: 10
the value is: 20
the value is: 30
the value is: 40
the value is: 50

위처럼 index를 기준으로 값이 5가 되는 시점에 반복이 중단된다. 하지만 이런 방식은 에러가 발생하기 쉽다. 정확한 길이의 index를 사용하지 못한다면 프로그램은 오류가 발생할 것이고, 이 방식은 느리다.
이유는 컴파일러가 실행 간에 반복문을 통해 반복될 때마다 요소에 대한 조건 검사를 수행하는 런타임 코드를 추가하기 때문이라고 한다.
이러한 코드일 때 효율적인 대안으로 for 키워드를 사용하는 것이라고 한다.

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a.iter() {
        println!("the value is: {}", element);
    }
}

위 코드의 결과는 이전에 while 키워드로 작성했던 것과 동일한 결과이다.
for 키워드를 사용한 반복문은 안전하고 간결하기 때문에 가장 보편적으로 사용된다고 한다.
이러한 사용을 위해서 Rust에서 기본 라이브러리로 제공하는 Range를 사용하게 된다.
Range는 한 숫자에서 다른 숫자 전까지 모든 숫자를 차례로 생성한다.
예시는 다음과 같다.

fn main() {
    for number in (1..4).rev() {
        println!("{}!", number);
    }
    println!("LIFTOFF!!!");
}

위 코드는 range(1..4) 를 역순하게 하는 rev 메소드를 사용한 카운트다운 프로그램이다.


현재 시리즈는 다음 링크를 공부한 내용을 기록하고 있습니다.
> The Rust Programming Language <


profile
내 인생이라는 프로젝트의 최고 버전을 만들기 위해

0개의 댓글