에러 Box하기
원본 에러를 보존하면서 단순한 코드를 작성하는 방법은 에러들을 Box하는 것입니다. 단점은 기저 에러 타입을 런타임에만 알 수 있고 정적으로 결정되지 않는다는 것입니다.
표준 라이브러리는 Box가 From을 통해 Error 트레이트를 구현하는 모든 타입으로부터 트레이트 객체 Box<Error>로의 변환을 구현하도록 함으로써 에러를 박싱하는 것을 돕습니다.
use std::error;
use std::fmt;
// 별칭이 `Box<dyn error::Error>`를 사용하도록 변경합니다.
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;
#[derive(Debug, Clone)]
struct EmptyVec;
impl fmt::Display for EmptyVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "두 배로 만들 첫 번째 항목이 유효하지 않습니다")
}
}
impl error::Error for EmptyVec {}
fn double_first(vec: Vec<&str>) -> Result<i32> {
vec.first()
.ok_or_else(|| EmptyVec.into()) // Into 트레이트를 사용하여 Box로 변환합니다.
.and_then(|s| {
s.parse::<i32>()
.map_err(From::from) // From::from 함수 포인터를 사용하여 Box로 변환합니다.
.map(|i| 2 * i)
})
}
fn print(result: Result<i32>) {
match result {
Ok(n) => println!("두 배가 된 첫 번째 값은 {}입니다", n),
Err(e) => println!("에러: {}", e),
}
}
fn main() {
let numbers = vec!["42", "93", "18"];
let empty = vec![];
let strings = vec!["두부", "93", "18"];
print(double_first(numbers));
print(double_first(empty));
print(double_first(strings));
}