Rust에서 오류를 처리할 때 Result와 panic!은 사용 목적이 다릅니다.
둘을 어떻게 구분해서 써야 하는지는 "이 오류를 예상 가능한가, 회복 가능한가"에 달려 있습니다.
Result<T, E>로 처리해야 할 경우 (예상 가능한 실패)사용자가 선택적으로 대응할 수 있는 상황에선 Result를 써야 합니다.
| 상황 예시 | 설명 |
|---|---|
| 파일 열기 | File::open()은 파일이 없을 수도 있고, 권한 없을 수도 있음 (예상 가능) |
| 사용자 입력 파싱 | str.parse::<i32>()는 잘못된 숫자 입력이 있을 수 있음 |
| 네트워크 요청 | 연결 실패, 타임아웃 등은 일반적인 운영 중 발생 가능 |
| DB 쿼리 | 쿼리 실패, 연결 오류 등 처리 가능성이 있는 오류 |
옵션에서 ok_or 변환 | Option<T> → Result<T, E>로 바꿔서 명시적으로 에러 다루기 |
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
panic!으로 처리해야 할 경우 (비정상 상황, 치명적 논리 오류)| 상황 예시 | 설명 |
|---|---|
| 명백한 프로그래머 실수 | unwrap()에서 None 나옴 → 로직 오류 |
| 인덱스 초과 | 벡터에서 존재하지 않는 index 접근 |
| 디버깅 중 불가능한 상태 확인 | match에서 모든 경우를 다뤘는데 unreachable!()까지 왔다면 논리적 버그 |
| 내부 불변성 깨짐 | 라이브러리 내부에서 절대 일어나지 않아야 하는 상태 |
fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("division by zero");
}
a / b
}
또는
fn get_element(vec: &Vec<i32>, index: usize) -> i32 {
vec.get(index).expect("Index out of bounds")
}
| 항목 | Result | panic! |
|---|---|---|
| 오류 종류 | 예상 가능, 회복 가능 | 예상 불가, 치명적 |
| 사용 대상 | 파일, 네트워크, 사용자 입력, DB 등 | 논리 오류, 버그, 계약 위반 |
| 누가 처리하나? | 호출자가 오류 처리 | 즉시 프로그램 종료 |
| 예시 | File::open(), parse() | unwrap(), panic!("불가능한 상태") |
- "이건 실패할 수도 있고, 사용자가 이 상황에 대해 무언가 조치할 수 있다" → Result
- "이건 절대 실패해서는 안 되며, 실패하면 프로그램을 중단시켜야 한다" → panic!
필요하시면 unwrap()을 안전하게 대체할 수 있는 방법(?, unwrap_or, match 등)도 알려드릴게요.