일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 클린코드
- 프레임워크
- 개발
- Baekjoon
- API
- 스프링
- 코딩
- 백준
- cleancode
- 그리디
- database
- 코딩테스트
- 자바
- 애자일기법
- 엘라스틱서치
- ES
- spring boot
- JPA
- Java
- 애자일프로그래밍
- 읽기쉬운코드
- 데이터베이스
- framework
- 그리디알고리즘
- 개발자
- 알고리즘
- Spring
- mongoDB
- Elasticsearch
- 코드
- Today
- Total
튼튼발자 개발 성장기🏋️
러스트 21 - 예외처리 #2 : Result<T, E> 본문
panic! 매크로가 복구 불가능한 에러를 처리하기 위함이라면, 복구 가능한 에러 처리를 위한 녀석은 Result<T, E>가 있다.
enum Result<T, E> {
Ok(T),
Err(E),
}
Result의 핵심!!!
- T와 E는 제네릭 타입 파라미터다.
- T는 성공한 후에 Ok variant 내에 반환될 값의 타입
- E는 실패한 후에 Err variant 내에 반환될 에러 타입
파일을 가지고 오는 코드를 보자.
use std::fs::File;
fn main() {
let file = File::open("hello.txt");
if file.is_ok() {
println!("SUCCESS!!! : {:?} ", file.ok());
} else {
println!("FAILE!!! : {:?}", file.err());
}
}
파일이 없으면 다른 파일을 읽는 다거나, 각각의 로직을 다르게 태울 수 있다는 이야기가 된다.
에러를 맵핑시켜보자.
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => panic!("파일 생성에 실패 : {:?}", e),
},
other_error => panic!("파일 로드 중에 문제 발생 : {:?}", other_error),
},
};
}
match를 사용하면 이러한 코드구현도 가능하다.
File::open이 반환하는 값의 타입은 io::Error이며 표준 라이브러리에서 제공하는 구조체다.
이 구조체에는 io::ErrorKind 값을 얻기 위해 kind라는 메소드가 있다.
io::ErrorKind는 표준 라이브러리에서 제공되며 io 작업으로 인해 발생할 수 있는 다양한 종류의 에러를 표현하는 variant를 가진 열거형이다. 상위 코드에서 사용하는 variant는 io::ErrorKind::NotFound라는 녀석이다.
1. 에러가 났을 때 panic을 위한 unwrap, expect
match는 충분히 사용 가능하지만, 의도를 정확하게 파악하기 어려울 수 있다.
result<T, E> 타입은 다양한 작업 수행을 위해 여러가지의 헬퍼 메소드가 정의되어 있다.
1. unwrap
match 표현식 처럼 구현되는 숏컷 메소드라고 한다.
- 결과 값이 Ok variant인 경우 unwrap은 Ok 내부의 값을 반환한다.
- 결과 값이 Err variant인 경우 unwrap은 panic! 매크로를 호출한다.
2. expect
unwrap과 유사하지만, panic! 매크로의 에러 메시지를 개발자 맘대로 할 수 있도록 해준다.
이렇게...!!!
use std::fs::File;
fn main() {
let f = File::open("hello.txt").expect("파일 오픈 실패!!!");
}
2. 에러 전파
구현이 실패 할 수도 있는(에러 발생) 함수를 작성할 때, 오류 처리를 해당 함수 내에서 할지, 혹은 호출한 녀석이 할지에 대한 고민은 누구나 했을 것이다.
use std::io;
use std::io::Read;
use std::fs::File;
fn read_userName_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
read_userName_from_file의 리턴 값은 Result. Ok라면 String, Err라면 io::Error를 리턴할 것이다.
러스트는 에러 전파 패턴이 굉장히 흔하게 발생되기 때문에, 물음표 연산자("?")를 제공한다.
use std::io;
use std::io::Read;
use std::fs::File;
fn read_userName_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
에러를 호출한 쪽으로 리턴하는 함수가 이렇게 간단해졌다.
Result 값 뒤에 ?는 이전 match 표현식과 같은 방식으로 동작 되도록 정의되어 있다. 만약 Result의 값이 Ok이면 Ok 내부의 값이 이 표현식에서 반환되고 프로그램은 계속 진행 될 것이다.
반대로, 값이 Err이면 오류 값이 리턴될 것이다.
'프로그래밍 > RUST' 카테고리의 다른 글
러스트 23 - Packages와 Crates, 그리고 Modules #1 : Packages와 Crates (0) | 2019.04.21 |
---|---|
러스트 22 - Packages와 Crates, 그리고 Modules (0) | 2019.04.21 |
러스트 20 - 예외처리 #1 : panic! (0) | 2019.04.14 |
러스트 19 - Collections #2 : Hash Map (0) | 2019.03.31 |
러스트 18 - Collections #1 : Vector (0) | 2019.03.31 |