
Rust 함수와 제어 흐름이 왜 중요한가요?
코드를 작성하다 보면 누구나 한 번쯤 마주하는 벽이 있어요. 바로 코드가 길어질수록 어디서 무엇을 하는지 파악하기 어려워지고, 조건이 복잡해질수록 논리가 꼬여버리는 상황이에요. 스파게티 코드처럼 엉켜버린 로직은 버그를 만들기 쉽고, 나중에 코드를 다시 볼 때도 엄청난 스트레스를 유발하죠.
Rust를 처음 배우는 입문자라면 더욱 당혹스러울 수 있어요. Rust는 다른 언어보다 엄격한 규칙을 가지고 있기 때문에, 함수를 어떻게 정의하고 제어 흐름을 어떻게 설계하느냐에 따라 컴파일러와의 싸움이 될 수도, 혹은 아주 든든한 지원군이 될 수도 있거든요.
함수를 적절하게 나누어 사용하면 반복되는 작업을 줄이고 코드의 가독성을 획기적으로 높일 수 있어요. 또한, Rust만의 독특한 제어 흐름 도구인 match나 강력한 반복문을 잘 활용하면, 다른 언어에서는 구현하기 까다로웠던 안전한 로직을 아주 우아하게 작성할 수 있답니다.
이 글을 끝까지 읽고 나면 여러분은 다음과 같은 능력을 갖추게 될 거예요.
- 복잡한 로직을 깔끔한 함수 단위로 쪼개는 설계 감각
- if, loop, match 등 상황에 맞는 최적의 제어문 선택 능력
- 컴파일러의 에러 메시지를 두려워하지 않고 제어 흐름을 교정하는 방법
- 실무에서 바로 쓸 수 있는 탄탄한 Rust 코드 작성 기초
시작 전 꼭 확인해야 할 준비 사항
Rust의 함수와 제어 흐름을 본격적으로 다루기 전에, 최소한의 환경과 개념적 토대가 갖춰져 있어야 해요. 아무 준비 없이 코드부터 치기 시작하면, 문법 에러가 발생할 때마다 원인을 찾느라 시간을 허비하게 될 거예요.
개발 환경 구축하기
가장 먼저 필요한 것은 Rust 툴체인이에요. 터미널에서 `rustc –version`을 입력했을 때 버전 정보가 잘 나온다면 준비는 끝난 셈이죠. 만약 설치되어 있지 않다면 rustup을 통해 설치하는 것이 가장 권장되는 방법이에요.
에디터는 VS Code를 강력하게 추천해요. 하지만 그냥 VS Code만 설치해서는 부족해요. rust-analyzer라는 확장 프로그램을 반드시 설치해야 해요. 이 도구가 있어야 함수의 매개변수 타입이나 제어 흐름의 오류를 실시간으로 잡아줄 수 있거든요. 이 도구가 있고 없고의 차이는 마치 내비게이션 없이 운전하는 것과 비슷해요.
기초 개념 체크리스트
함수와 제어 흐름을 배우기 전에 다음 개념들을 가볍게 훑어보셨는지 확인해 보세요. 완벽히 알 필요는 없지만, 용어 정도는 익숙해야 해요.
- 변수 불변성(Immutability): Rust 변수는 기본적으로 값을 바꿀 수 없다는 점
- 기본 타입(Scalar Types): 정수, 부동 소수점, 불리언 등
- 표현식과 문(Expression vs Statement): 값을 반환하는 것과 명령을 수행하는 것의 차이
Rust는 문(Statement)보다 표현식(Expression)을 선호하는 경향이 있어요. 제어 흐름을 다룰 때 이 차이를 이해하는 것이 매우 중요해요.
상황별 제어 흐름 선택 기준
어떤 제어문을 쓸지 고민될 때 참고할 수 있는 기준표를 만들어 보았어요.
| 제어 흐름 유형 | 주요 특징 | 권장 사용 상황 |
|---|---|---|
| if / else | 단순한 조건 비교 | 참/거짓이 명확한 이분법적 결정 |
| match | 강력한 패턴 매칭 | 여러 가능성을 모두 안전하게 처리할 때 |
| loop | 무한 반복 | 특정 조건이 될 때까지 끝없이 돌려야 할 때 |
| for | 컬렉션 순회 | 배열이나 범위 내의 값을 차례로 꺼낼 때 |
Rust 함수와 제어 흐름의 핵심 구현 단계
이제 본격적으로 코드를 작성하며 원리를 파헤쳐 볼게요. 단순히 문법을 외우는 것이 아니라, 왜 이렇게 써야 하는가에 집중해서 따라와 주세요.
STEP 1. 함수 정의와 매개변수 활용하기
함수는 특정 작업을 수행하는 코드의 묶음이에요. Rust에서 함수를 만들 때는 `fn` 키워드를 사용하죠. 가장 기본적인 형태는 다음과 같아요.
먼저, 매개변수를 받는 함수를 만들어 볼게요. 매개변수의 타입은 반드시 명시해야 해요. Rust의 엄격함이 여기서 드러나죠. 타입이 명확해야 컴파일러가 메모리 구조를 정확히 파악할 수 있기 때문이에요.
값을 반환할 때는 `->` 기호를 사용해요. 여기서 주의할 점은 마지막 줄에 세미콜론(`;`)을 붙이느냐 아니냐에 따라 반환 여부가 결정된다는 거예요. 세미콜론이 있으면 문(Statement)이 되어 값을 반환하지 않고, 없으면 표현식(Expression)이 되어 그 값이 반환돼요. 이 차이를 모르면 한참을 헤매게 될 거예요.
반환 타입이 있는 함수에서 마지막에 세미콜론을 잘못 붙이면 ‘함수가 값을 반환하지 않는다’는 에러가 발생하니 꼭 확인하세요!
STEP 2. 조건문을 통한 논리 제어 (if/else)
가장 흔하게 쓰이는 조건문은 `if`와 `else`예요. 다른 언어와 비슷해 보이지만, Rust의 `if`는 표현식이라는 점이 핵심이에요. 즉, `if` 문 자체의 결과값을 변수에 바로 대입할 수 있어요.
예를 들어, 점수에 따라 합격 여부를 판단하는 변수를 만들 때 `let result = if score >= 60 { “Pass” } else { “Fail” };`와 같이 작성할 수 있어요. 이는 코드를 훨씬 간결하고 읽기 좋게 만들어 주죠. 단, `if`와 `else` 블록에서 반환하는 데이터의 타입은 반드시 일치해야 해요. 한쪽은 숫자인데 다른 쪽은 문자열이면 컴파일러가 허락하지 않아요.
STEP 3. 강력한 패턴 매칭, match 활용법
Rust의 꽃이라고 불리는 `match`를 빼놓을 수 없어요. `match`는 단순히 여러 조건을 검사하는 것을 넘어, 데이터의 구조를 분석하는 패턴 매칭을 수행해요.
가장 큰 장점은 완전성(Exhaustiveness)이에요. 모든 가능한 경우의 수를 다 다루지 않으면 컴파일러가 에러를 내뱉어요. 이게 처음에는 귀찮게 느껴질 수 있지만, 결과적으로 런타임에 발생할 수 있는 예상치 못한 에러를 사전에 차단해 주는 엄청난 안전장치가 돼요.
예를 들어, 어떤 숫자가 1, 2, 3 중 하나인지 확인하는 상황이라면 `match`는 모든 경우를 체크하라고 강요하죠. 만약 숫자가 4일 경우를 대비하지 않았다면, Rust는 코드를 실행시켜 주지 않아요. 이렇게 철저하게 검사하기 때문에 Rust 코드는 매우 신뢰도가 높답니다.
STEP 4. 다양한 반복문(loop, while, for) 마스터하기
프로그래밍의 핵심은 반복이에요. Rust는 목적에 따라 세 가지 반복문을 제공해요.
- loop: 무한 루프를 돌 때 사용해요. 특정 조건에서 `break`를 사용하여 탈출해야 해요. 가장 원초적이고 강력한 형태예요.
- while: 특정 조건이 참인 동안에만 반복해요. 조건이 거짓이 되는 순간 멈추죠.
- for: 가장 권장되는 반복문이에요. 범위(range)나 배열 같은 컬렉션을 순회할 때 사용하며, 인덱스 에러로부터 가장 안전해요.
실제로 숫자를 1부터 5까지 출력하는 간단한 시나리오를 생각해 볼게요. `for i in 1..=5 { println!(“{}”, i); }`라고 쓰면 아주 깔끔하게 실행돼요. 여기서 `1..=5`는 1부터 5까지 포함한다는 뜻이에요. `1..5`라고 쓰면 5는 포함되지 않으니 주의하세요!
[실습 시나리오] 간단한 계산기 로직 구현하기
위에서 배운 내용을 종합해서 작은 로직을 설계해 볼까요? 사용자의 입력값과 연산자를 받아 결과를 내놓는 구조를 상상해 보세요.
- `calculate(a: i32, b: i32, operator: char) -> i32` 함수를 정의합니다.
- 함수 내부에서는 `match operator`를 사용하여 ‘+’, ‘-‘, ‘*’, ‘/’ 각 케이스를 처리합니다.
- 각 케이스는 산술 연산을 수행하고 그 결과를 반환합니다.
- `match`를 통해 예상치 못한 연산자(예: ‘?’)가 들어왔을 때의 예외 처리(panic)도 포함합니다.
이런 식으로 함수와 제어 흐름을 결합하면, 복잡한 계산 로직도 매우 체계적으로 관리할 수 있게 돼요.
자주 하는 실수와 해결법
Rust를 배우다 보면 누구나 겪는 고비가 있어요. 특히 함수와 제어 흐름 부분에서 자주 발생하는 실수들을 정리해 드릴게요. 이것만 알아도 삽질하는 시간을 절반으로 줄일 수 있어요.
- ❌ 함수 마지막 줄에 세미콜론을 붙여 값을 못 돌려줌
→ 왜 발생하는가: Rust에서 세미콜론은 해당 문장을 ‘끝내는’ 역할을 해요. 값을 반환하려면 세미콜론이 없는 ‘표현식’ 상태여야 해요.
✅ 해결법: 반환할 값 뒤의 세미콜론을 제거하세요. - ❌ match 문에서 모든 경우의 수를 다루지 않음
→ 왜 발생하는가: Rust는 안전을 위해 모든 가능성을 검사하길 원해요.
✅ 해결법: `_ => { … }`를 사용하여 나머지 모든 경우(default case)를 명시하세요. - ❌ if 문에서 반환하는 두 블록의 타입이 다름
→ 왜 발생하는가: `if`가 표현식으로 쓰일 때, 결과값은 항상 하나의 타입이어야 하기 때문이에요.
✅ 해결법: 양쪽 블록에서 반환하는 데이터 타입을 동일하게 맞춰주세요. - ❌ for 루프 범위 설정 오류
→ 왜 발생하는가: `1..5`와 `1..=5`의 차이를 혼동하는 경우가 많아요.
✅ 해결법: 마지막 숫자를 포함하고 싶다면 반드시 `=`(equal)을 붙여서 `..=`를 사용하세요. - ❌ 무한 루프에 빠짐
→ 왜 발생하는가: `loop`를 사용하면서 탈출 조건인 `break`를 적절한 위치에 넣지 않았기 때문이에요.
✅ 해결법: 루프 내부에서 조건을 체크하고 `break` 키워드로 빠져나오는 로직을 반드시 넣으세요.
자주 묻는 질문
Q. 함수에서 여러 개의 값을 한 번에 반환하고 싶을 때는 어떻게 하나요?
A. Rust에서는 튜플(Tuple)을 사용하면 아주 간단하게 해결할 수 있어요. 예를 들어 `fn get_coords() -> (i32, i32)`와 같이 선언하면 두 개의 정수를 동시에 돌려줄 수 있답니다.
Q. if 문과 match 문 중 어떤 것을 쓰는 게 더 좋은가요?
A. 조건이 단순한 참/거짓이라면 `if`가 편해요. 하지만 비교해야 할 대상이 많거나, 열거형(Enum) 같은 복잡한 데이터 구조를 다룬다면 `match`를 사용하는 것이 훨씬 안전하고 강력해요.
Q. match 문에서 `if let`을 사용한다는 말을 들었는데 무엇인가요?
A. `if let`은 `match` 문을 아주 단순하게 줄여 쓴 형태예요. 단 하나의 패턴만 관심 있고 나머지는 무시해도 될 때 사용하면 코드가 훨씬 간결해져요.
Q. 함수 인자로 값을 넘길 때 소유권 문제가 생기면 어떻게 하죠?
A. 값을 통째로 넘기지 말고, 참조자(`&`)를 사용하여 값을 빌려주는 방식을 사용해 보세요. 그러면 소유권 이전 없이도 함수 내에서 값을 안전하게 사용할 수 있어요.
실력을 한 단계 높이는 마무리 전략
지금까지 Rust의 함수와 제어 흐름을 어떻게 사용하는지 핵심 위주로 살펴보았어요. 처음에는 문법이 까다롭고 컴파일러가 자꾸 에러를 던져서 힘들 수 있지만, 그만큼 여러분의 코드를 안전하게 지켜주고 있다는 증거이니 너무 낙담하지 마세요.
- 함수는 `fn` 키워드로 정의하며, 매개변수 타입 명시는 필수예요.
- 반환값은 마지막 줄에 세미콜론을 빼서 표현식으로 만들어 전달해요.
- `if`는 단순 조건, `match`는 복잡한 패턴 매칭에 사용해요.
- `match`를 쓸 때는 모든 경우의 수를 다 다뤄야 안전해요.
- 반복문은 순회 목적이라면 `for` 루프를 가장 권장해요.
- 에러가 나면 컴파일러의 메시지를 읽고, 소유권과 타입 일치 여부를 확인하세요.
배운 내용을 머리로만 아는 것과 직접 손으로 짜보는 것은 하늘과 땅 차이에요. 오늘 배운 내용을 바탕으로 다음 단계들을 실천해 보세요.
- 오늘 할 일: 알려드린 간단한 계산기 시나리오를 직접 코드로 구현해 보기
- 이번 주 할 일: Rust 공식 문서(The Rust Programming Language)의 함수 섹션 다시 읽어보기
- 실행 직전 할 일: VS Code에 `rust-analyzer`가 제대로 작동하는지 확인하기
이 단계들을 차근차근 따라 하다 보면, 어느덧 Rust의 강력한 시스템을 자유자재로 다루는 자신을 발견하게 될 거예요. 이 과정이 어렵게 느껴진다면, 이전에 작성했던 Rust 함수와 제어 흐름 관련 다른 글들을 다시 한번 복습해 보는 것도 큰 도움이 된답니다.
이 단계대로 따라 하며 Rust 함수와 제어 흐름을 직접 구현해 보세요! 여러분의 멋진 Rust 개발 여정을 응원합니다.