[Rust] 제어 흐름: 조건문과 반복문

이 글은 The Rust Programming Language 3.5장 "Control Flow"을 읽고 정리한 내용이에요. 예제도 이 장의 예제를 바탕으로 했어요.

프로그램이 조건에 따라 특정 코드를 실행하거나, 특정 조건이 만족되는 동안 코드를 반복해서 실행하도록 만드는 것은 모든 프로그래밍 언어의 기본이에요. Rust에서는 크게 if 표현식과 loop, while, for 같은 반복문으로 이를 제어해요.


1. if 표현식 (if Expressions)

if 표현식은 조건에 따라 코드의 실행 경로를 나눠요. "이 조건이 맞으면 이 코드를 실행하고, 아니면 실행하지 마라"라고 지시하는 거예요.

기본적인 사용법

가장 기본적인 형태는 if와 else의 조합이에요.

Rust
fn main() {
    let number = 3;

    if number < 5 {
        println!("조건이 참입니다");
    } else {
        println!("조건이 거짓입니다");
    }
}
  • 조건식: if 키워드 뒤에 오는 조건(위 예시의 number < 5)은 반드시 결과가 불리언(bool) 타입이어야 해요.
  • Arms: 조건이 참일 때 실행되는 {} 블록을 '갈래(arm)'라고 불러요.
  • 엄격한 타입 체크: Rust는 다른 언어(JS, Ruby 등)와 달리 숫자를 자동으로 불리언으로 바꾸지 않아요. 그래서 if number { ... } 같은 코드는 컴파일 에러가 나고, if number != 0처럼 명시적으로 비교해야 해요.

else if로 여러 조건 처리하기

여러 조건을 차례로 확인해야 할 때 써요.

Rust
fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("4로 나누어 떨어집니다");
    } else if number % 3 == 0 {
        println!("3으로 나누어 떨어집니다");
    } else {
        println!("나머지 경우입니다");
    }
}

참고: Rust는 위에서부터 검사하며 가장 먼저 참이 되는 블록 하나만 실행하고 나머지는 건너뛰어요. 조건이 너무 많아지면 나중에 배울 match를 쓰는 게 더 깔끔해요.

let 구문에서 if 사용하기

Rust에서 if는 표현식(expression) 이에요. 실행 결과로 값을 내놓는다는 뜻이에요. 그래서 변수에 값을 바로 할당할 수 있어요.

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

    println!("number의 값: {number}");
}
  • 타입 일치: if 블록과 else 블록이 반환하는 값의 타입이 같아야 해요. 한쪽은 정수, 한쪽은 문자열이면 컴파일 에러가 나요.

2. 반복문 (Repetition with Loops)

Rust에는 loop, while, for 세 가지 반복문이 있어요.

무한 반복 loop

loop는 명시적으로 중단 명령(break)을 내리기 전까지 계속 반복해요.

Rust
fn main() {
    loop {
        println!("다시 실행!");
        break; // 이 키워드가 있어야 멈춰요.
    }
}

루프에서 값 반환하기

loop는 작업을 재시도한 뒤 그 결과를 밖으로 전달할 때 유용해요. break 뒤에 값을 적으면 루프 밖으로 그 값이 반환돼요.

Rust
fn main() {
    let mut counter = 0;
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2;
        }
    };
    println!("결과: {result}"); // 20 출력
}

루프 라벨 (Loop Labels)

여러 루프가 겹쳐있을 때(중첩 루프), 안쪽 루프에서 바깥쪽 루프를 한 번에 끝내고 싶다면 라벨을 써요. 라벨은 항상 '(작은따옴표)로 시작해요.

Rust
fn main() {
    let mut count = 0;
    'counting_up: loop {
        let mut remaining = 10;
        loop {
            if remaining == 9 { break; }
            if count == 2 { break 'counting_up; }
            remaining -= 1;
        }
        count += 1;
    }
}

조건부 반복 while

조건이 참인 동안에만 루프를 돌리고 싶을 때 써요.

Rust
fn main() {
    let mut number = 3;
    while number != 0 {
        println!("{number}!");
        number -= 1;
    }
    println!("LIFTOFF!!!");
}

컬렉션 순회 for

배열이나 리스트 같은 데이터를 하나씩 꺼내어 처리할 때는 for가 가장 안전하고 효율적이에요.

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

    for element in a {
        println!("값: {element}");
    }
}
  • 안전성: while문을 써서 인덱스(a[i])로 접근하는 방식은 인덱스 범위를 벗어날 위험이 있지만, for는 컬렉션의 끝을 알아서 파악해서 안전해요.
  • Range 사용: 특정 횟수만큼 반복하고 싶을 때는 범위를 지정하는 (1..4) 같은 방식을 써요. .rev()를 붙이면 순서를 뒤집을 수도 있어요.

요약

  1. if: 조건에 따른 분기예요. 조건은 반드시 bool이어야 하고, 값을 반환할 수 있어요.
  2. loop: 무한 반복이에요. break와 함께 값을 반환하는 패턴으로 자주 써요.
  3. while: 조건이 참인 동안 반복해요.
  4. for: 컬렉션과 범위를 순회할 때 가장 안전하고 많이 쓰는 방식이에요.