16.4 Multiple error types
이전 예제는 항상 매우 편리했다; Result
는 다른 Result
와 그리고 Option
은 다른 Option
들과 상호작용 했다.
어떨 때는 Option
이 Result
와 상호작용 할 필요가 있거나, Result<T, Error1>
이 Result<T, Error2>
와 상호작용 할 필요가 있다. 이런 경우 때문에 우리의 다양한 에러 타입들을 관리하여 이들을 쉽게 상호작용 할 수 있도록 만들고자 하는 것이다.
다음의 코드에서, 두 인스턴스가 unwrap
되어 다른 에러 타입을 만든다. Vec::first
는 Option
을 반환하고 parse::<i32>
는 Result<i32, ParseIntError>
를 반환한다:
fn double_first(vec: Vec<&str>) -> i32 {
let first = vec.first().unwrap(); // Generate error 1
2 * first.parse::<i32>().unwrap() // Generate error 2
}
fn main() {
let empty = vec![];
let strings = vec!["tofu", "93", "18"];
println!("The first doubled is {}", double_first(empty));
// Error 1: the input vector is empty
println!("The first doubled is {}", double_first(strings));
// Error 2: the element doesn't parse to a number
}
연결자에 대한 우리의 지식을 활용하여, 우리는 상기 예제를 명시적으로 에러 처리를 하게끔 재작성할 수 있다. 두 다른 타입의 에러가 일어난 후에, 우리는 이들을 String
고 같은 범용 타입으로 변경해야 한다.
이를 위해, 우리는 Option
과 Result
를 Result
들로 변형하고, 그들의 에러들을 동일 타입으로 map한다:
// 에러 타입으로 `String` 사용 type Result<T> = std::result::Result<T, String>; fn double_first(vec: Vec<&str>) -> Result<i32> { vec.first() // 값이 있을 시 `Option`을 `Result`로 변환. // 그렇지 않으면, 이 `String`을 포함하는 `Err`를 제공. .ok_or("Please use a vector with at least one element.".to_owned()) .and_then(|s| s.parse::<i32>() // `parse`가 얻는 에러를 `String`에 맵핑한다. .map_err(|e| e.to_string()) // `Result`은 새로운 리턴 타입이고, // 이제 내부 숫자를 두 배로 늘릴 수 있다. .map(|i| 2 * i)) } fn print(result: Result<i32>) { match result { Ok(n) => println!("The first doubled is {}", n), Err(e) => println!("Error: {}", e), } } fn main() { let empty = vec![]; let strings = vec!["tofu", "93", "18"]; print(double_first(empty)); print(double_first(strings)); }
다음 섹션에서, 명시적으로 에러를 처리하는 다른 방법을 살펴본다.