NeuroWhAI의 잡블로그
[Rust] 중첩 Result 사용. 본문
Error Handling in a Correctness-Critical Rust Project
sled home documentation support blog introduction to sled motivating experiences error handling in Rust Error Handling in a Correctness-Critical Rust Project Let’s begin with two excerpts from the paper Simple Testing Can Prevent Most Critical Failures: An
sled.rs
에러를 올바르게 다루는 방법에 대한 글에서 나온 중첩 Result 사용 예가 인상깊어서 가져왔습니다.
보통의 Rust 에러 처리 방식은 아래와 같습니다.
enum Error {
Io(std::io::Error),
CompareAndSwap(CompareAndSwapError),
}
에러 타입을 선언하고
fn compare_and_swap(
&mut self,
key: Key,
old_value: Value,
new_value: Value
) -> Result<(), sled::Error>
Result와 함께 씁니다.
그런데 여기 문제가 있습니다.
CompareAndSwap 에러는 지극히 정상적인 상황에서도 발생 가능한 것이고 올바르게 즉시 처리되어줘야 합니다.
Io 에러는 그렇지 않아서 시스템을 종료시켜야 한다고 합시다.
위 시나리오를 올바르게 다루려면 아래와 같이 에러를 처리해야 합니다.
let result = sled.compare_and_swap(
"dogs",
"pickles",
"catfood"
);
match result {
Ok(()) => {},
Err(sled::Error::Io(io_error)) =>
return Err(io_error.into()), // 비정상적인 상황!
Err(sled::Error::CompareAndSwap(cas_error)) => {
// 예상된 에러 처리.
}
}
근데 사람은 실수를 할 수 있기 때문에 compare_and_swap 함수를 쓸 때 저런 에러 처리 루틴을 까먹고 못 지킬 수 있습니다.
그냥 `unwrap`을 써버리거나 `try!`나 `?`로 에러 종류에 상관없이 밖으로 전파시킬 우려가 있죠.
이걸 중첩 Result로 해결할 수 있다고 합니다.
fn compare_and_swap(
&mut self,
key: Key,
old_value: Value,
new_value: Value
) -> Result<Result<(), CompareAndSwapError>, sled::Error>
이렇게 보기 안 좋게 바꾸는 것입니다.
그러면 에러 처리 루틴이 아래와 같이 단순화됩니다.
// try `?`를 써도 문제 없음.
let cas_result = sled.compare_and_swap(
"dogs",
"pickles",
"catfood"
)?;
if let Err(cas_error) = cas_result {
// 예상된 에러 처리.
}
`?`로 가장 바깥의 Result를 처리하면 비정상적인 상황(IO 에러)일 때만 오류가 밖으로 전파되고 그 외의 성공 상태나 예상된 에러일 땐 내부 실행 흐름이 유지됩니다.
그러니 다음에 얻은 내부 Result를 이용하여 예상된 에러를 처리해주면 됩니다.
반환형이 눈에 띄고 의도를 잘 보여주며 제대로 된 형식으로 처리하지 않으면 컴파일 경고나 에러를 볼 것이라 제대로 된 형태로 에러를 처리할 수 밖에 없게 됩니다.
'개발 및 공부 > 언어' 카테고리의 다른 글
[Rust] do-while (0) | 2020.05.03 |
---|---|
[Rust] Generics와 Associated Types (0) | 2020.04.04 |
[Rust] 직접 block_on 함수 만들기 (포스팅 소개) (0) | 2020.01.31 |
[C++] Concept 맛보기 (1) | 2020.01.10 |
[Rust] Pin과 Unpin 설명. (0) | 2019.09.26 |