Rust에는 Error Handling을 할 때 Result
라는 타입을 사용한다. Result
는 Ok
와 Err
로 나뉘는데, Ok
는 과제를 성공적으로 수행했을 때 내보내는 값이고 Err
는 과제 수행 중에 발생한 오류를 나타낸다.
enum Result<T, E> {
Ok(T),
Err(E),
}
예를 들어 어떤 문자열을 정수로 파싱하는 경우, 성공적으로 정수로 변환할 수 있지만 빈 문자열이나 숫자가 아닌 다른 문자가 포함된 경우에는 정수로 파싱할 수 없다. 그래서 parse
함수는 Result
를 반환해 정수 변환에 성공했는지 실패했는지 결과를 넘겨준다.
let num = input.parse::<i32>();
let num = match num {
Ok(n) => n,
Err(error) => panic!("Input a valid number."),
};
Result
를 반환하는 함수를 호출할 때는 반환값 처리를 위해 자주 match
를 사용한다. 그래서 Result
는 자주 사용하는 처리 방법을 함수로 제공한다.
만약 위의 코드처럼 Ok
를 받으면 그 안의 값을 꺼내고, Err
를 받으면 panic을 발생시키려 한다면 unwrap
이나 expect
를 사용하면 된다.
let num = input.parse::<i32>().unwrap();
// or
let num = input.parse::<i32>().expect("`input` is not vaild.");
만약 작성하고 있는 함수가 에러를 발생할 수 있는 동작을 수행한다면, 보통 함수 내에서 에러 처리를 하지 않고 Result
를 반환하도록 함수를 작성한다. 이처럼 호출자에게 Result
를 넘겨 호출자가 에러를 처리하는 방식을 propagating errors 라고 한다.
fn read_line_from_file() -> Result<String, io::Error> {
let mut file = match File::open("input.txt") {
Ok(file) => file,
Err(error) = return Err(error),
};
let mut input = String::new();
match file.read_to_string(&mut input) {
Ok(_) => Ok(input),
Err(error) => Err(Error),
}
}
propagating errors도 자주 보이는 패턴이라 축약 표기가 존재한다. Result
를 반환하는 함수 뒤에 ?
를 붙이면 된다. 해당 함수가 Ok
를 반환하면 그 안의 값을 그대로 넘겨주고 계속 함수를 실행하지만, Err
를 받으면 그 Err
자체를 현재 실행되는 함수 자체의 반환값으로 넘긴다.
fn read_line_from_file() -> Result<String, io::Error> {
let mut file = match File::open("input.txt")?;
let mut input = String::new();
file.read_to_string(&mut input)?;
Ok(input)
}
// shorter way
fn read_line_from_file() -> Result<String, io::Error> {
let mut input = String::new();
File::open("input.txt")?.read_to_string(&mut input)?;
Ok(input)
}
에러의 종류가 여러가지로 예상된다면 반환되는 에러 타입을 Box<dyn error::Error>
로 지정하면 된다.
'Archive > Rust' 카테고리의 다른 글
[Rustlings] 13. Option (0) | 2021.05.30 |
---|---|
[Rustlings] 12. Generic (0) | 2021.05.29 |
[Rustlings] 10. String (0) | 2021.05.26 |
[Rustlings] 9. collection (0) | 2021.05.25 |
[Rustlings] 8. module (0) | 2021.05.22 |