⚠️
Result와 ? 연산자 — Rust의 에러 처리 패턴
try-catch 없이 에러를 타입으로 다루는 방법
Java/Python은 try-catch로 에러를 잡는다. 문제는 어떤 함수가 어떤 예외를 던지는지 시그니처만 보고 알 수 없다는 점이다. Rust는 에러를 타입 시스템 안에 넣었다.
Result<T, E> — T가 성공값, E가 에러값. 함수 시그니처를 보면 이 함수가 실패할 수 있는지, 실패하면 어떤 에러인지 바로 알 수 있다.
fn read_file(path: &str) -> Result<String, io::Error> {
let content = fs::read_to_string(path)?; // 실패하면 에러를 바로 반환
Ok(content)
}
?가 핵심이다. Err면 즉시 반환, Ok면 안의 값을 꺼낸다. try-catch보다 간결하면서 에러 전파 경로가 명시적이다.
unwrap()은 에러 시 패닉(크래시)한다. 프로토타이핑에는 편하지만 프로덕션에서는 쓰면 안 된다.
핵심 포인트
1
실패 가능한 함수는 Result<T, E>를 반환한다
2
? 연산자로 에러를 호출자에게 자동 전파
3
match나 map_err로 에러를 변환/처리
4
thiserror/anyhow crate로 커스텀 에러 타입 정의
장점
- ✓ 함수 시그니처만 보면 에러 가능성을 알 수 있다
- ✓ ? 연산자로 에러 전파가 간결하다
단점
- ✗ 에러 타입 변환(From trait)이 처음엔 번거롭다
- ✗ unwrap 남용 유혹이 크다
사용 사례
파일/네트워크 I/O — 실패가 정상적인 흐름의 일부
CLI 도구 — 사용자 입력 검증 에러를 우아하게 표시