제어 흐름은 프로그램의 실행 순서를 결정하는 핵심 개념이다. Rust에서는 조건 분기, 반복, 패턴 매칭 등을 사용하여 다양한 흐름을 설계할 수 있다. 프로그램이 복잡해질수록 제어 흐름 구조를 적절히 활용하는 것이 중요하다. 이 절에서는 Rust에서 제공하는 제어 흐름 요소들을 어떻게 실전적으로 조합하고 활용하는지에 대해 예시 코드를 중심으로 자세히 다룬다.
조건문은 프로그램의 동작 흐름을 유연하게 구성하는 데 필수적이다. Rust에서는 if 구문을 통해 조건에 따라 분기 처리를 할 수 있으며, match 구문을 통해 보다 다양한 패턴을 간결하게 처리할 수 있다. 또한 반복문은 loop, while, for와 같은 다양한 형태를 지원한다. 이 모든 요소를 적절히 조합하면, 복잡한 로직을 깔끔하고 효율적으로 구현할 수 있다.
아래 예시는 여러 종류의 제어 흐름 구조를 합쳐서 사용하는 방식에 초점을 맞춘다. 사용자가 숫자를 입력하면 특정 구간에 따라 문구를 출력하고, 조건에 따라서 반복을 멈추거나 계속 진행하는 단순한 시뮬레이션이다. 코드의 동작 과정을 자세히 살펴보면 제어 흐름이 어떻게 결합되어 있는지를 알 수 있을 것이다.
use std::io;
fn main() {
let mut count = 0;
loop {
println!("정수를 입력하라 (0이면 종료):");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("입력 오류");
// 입력값을 숫자로 변환
let num: i32 = match input.trim().parse() {
Ok(n) => n,
Err(_) => {
println!("유효한 숫자를 입력하라.");
continue;
}
};
// 0이 들어오면 반복 종료
if num == 0 {
println!("프로그램을 종료한다.");
break;
}
// 조건에 따른 분기
if num > 0 {
println!("양수이다.");
if num < 10 {
println!("한 자릿수 양수이다.");
} else if num < 100 {
println!("두 자릿수 양수이다.");
} else {
println!("세 자릿수 이상의 양수이다.");
}
} else {
println!("음수이다.");
if num > -10 {
println!("한 자릿수 음수이다.");
} else if num > -100 {
println!("두 자릿수 음수이다.");
} else {
println!("세 자릿수 이상의 음수이다.");
}
}
// 패턴 매칭을 활용한 간단한 예시
match num {
1 => println!("특별히 1을 입력하였다."),
10 | 100 => println!("10 또는 100을 입력하였다."),
_ => println!("기타 숫자를 입력하였다."),
}
count += 1;
println!("지금까지 {}번 입력을 받았다.\n", count);
}
}
이 코드는 사용자 입력을 받고 숫자에 따라 다양한 분기 처리를 수행한 뒤, 조건이 충족되면 반복을 중단하거나 계속하도록 제어한다. 코드 구성에서 눈여겨볼 부분은 조건문과 match를 함께 사용하는 점, 그리고 적절한 시점에 break와 continue를 사용하여 루프의 흐름을 끊거나 이어가는 것이다.
if 구문은 조건이 단순하거나 논리식이 명확할 때 사용하기 좋다. 위의 예시에서는 num이 0과 같거나 큰지, 혹은 작은지를 분기하는 데 if를 사용했다. match 구문은 값에 따라 여러 갈래로 분기해야 할 때 가독성을 높이고 오류를 줄이기 위해 유용하다. 위의 예시에서는 num의 특정 값(예: 1, 10, 100)을 처리할 때 match를 활용했다.
반복문에 대해서는 loop, while, for를 적절한 상황에 따라 달리 사용할 수 있다. 위 예시에서는 조건이 명확하지 않고 특정 이벤트(사용자가 0을 입력) 발생 시 종료하는 구조가 적합하므로 loop를 선택했다. 반복을 계속하면서 입력값이 유효한지 검사할 때, 유효하지 않다면 루프의 다음 단계로 건너뛰게 하기 위해 continue를 사용했다. 이처럼 반복문을 설계할 때는 종료 조건과 반복 중단 혹은 건너뛰기 조건 등을 분명히 제어해주어야 한다.
좀 더 복잡한 상황에서는 함수나 구조체 등 더 고수준의 추상화를 활용해 제어 흐름을 깔끔하게 분리하기도 한다. 하지만 이러한 작은 예시들을 충분히 익히고 조합하는 훈련을 쌓으면, 복잡한 로직도 잘게 쪼개어 효율적이고 가독성 있는 제어 흐름을 설계할 수 있다.
제어 흐름 문법은 Rust를 포함한 대부분의 언어에서 비슷한 원리를 공유한다. 다만 Rust는 패턴 매칭(match)과 같은 풍부한 언어 기능을 제공하므로, C나 Java 등에 익숙한 프로그래머도 match를 활용해 효율적인 제어 흐름 구성을 시도해볼 수 있다. 특히 match에서 _와 같은 와일드카드 패턴, 여러 값을 한꺼번에 처리할 수 있는 구문(예: 10 | 100), 가변 범위를 처리하는 구문(예: 0..10) 등을 잘 이해한다면, 명료한 분기 처리가 가능하다.
제어 흐름을 다루는 핵심 포인트는 프로그램이 처리해야 하는 로직을 명확히 파악하는 것이다. 간단한 로직이라면 if와 loop만으로 충분하겠지만, 다단 분기나 복잡한 흐름이 필요한 경우에는 match 구문과 다양한 반복문을 적절히 배치하여 로직을 깔끔하게 유지해야 한다. 이렇게 정리된 제어 흐름 구조는 코드를 유지보수하기 쉽게 만들고, 프로그램의 실행 흐름을 예측하기도 수월하게 한다.
제어 흐름은 모든 프로그램에 필수적이므로, 작은 예시부터 꾸준히 연습하면서 자연스럽게 익히는 것이 중요하다. 앞으로의 예제나 실제 개발 과정에서 if, match, 반복문 등을 적극적으로 활용해보고, Rust의 특징적인 부분인 소유권이나 패턴 매칭과의 결합도 함께 살펴보는 것이 좋다. 이러한 과정을 통해, Rust에서의 제어 흐름을 자유자재로 다룰 수 있게 될 것이다.