러스트에는 자바나 C++와 같은 전통적인 예외가 없습니다. 대신 오류를 반환하기 위해 'Result' 및 'Option' 래퍼 타입이 사용됩니다.
Result<T, E> — 값(Ok(T)) 또는 오류(Err(E))를 저장합니다. 일반적으로 올바르게 수행되지 않을 수 있는 작업(예: 파일 입출력)에 사용됩니다.
Option<T> — 선택적 값에 대해: Some(T) 또는 None, 오류 정보가 없습니다. 예:
fn divide(x: f64, y: f64) -> Option<f64> { if y == 0.0 { None } else { Some(x / y) } }
러스트에는 try/catch 스타일의 예외가 없는데, 이는 투명하고 관리 가능한 오류 흐름을 보장하고 예외를 유지하기 위해 가비지 컬렉터나 unwind 엔진이 필요하지 않도록 하기 위함입니다.
왜 panic!을 일반 오류 처리에 사용할 수 없는가요?
답변: panic!은 실행 흐름을 종료하여 복구할 수 없게 하며, unwinding/abort를 초래합니다. 반대로, 오류가 Result를 통해 반환되면 호출 측에서 이를 처리할 수 있습니다. 예:
fn foo() -> Result<(), String> { Err("문제가 발생했습니다".to_string()) } // 대신 fn foo() { panic!("문제가 발생했습니다"); }
이야기
이미지 처리를 위한 마이크로서비스에서 개발자는 모든 비정상 상황을 처리하기 위해
panic!을 사용했습니다. 이로 인해 오류가 발생할 때마다 서비스가 중단되었고, 클라이언트에게 오류 세부 정보를 포함한 적절한 HTTP 응답이 반환되지 않았습니다.
이야기
CLI 도구에서 모든 입출력을 위해
unwrap()을 사용했으며, 발생할 수 있는 오류를 처리하지 않았습니다. 결과적으로 파일 시스템 오류가 발생했을 때 프로그램은 아무런 메시지나 진단 없이 종료되었습니다.
이야기
분석 서비스에서는 사소한 오류마다 Option을 사용하려고 했고, 이로 인해 오류 정보가 손실되어 디버깅이 어려워졌습니다. 오류가 있는 열거형을 사용하여 Result로 전환한 이후 버그를 찾고 수정하는 것이 쉬워졌습니다.