Rust에서는 에러를 처리하는데 몇 가지 기능이 있는데 그 중 panic
과 Result
에 대해 공부해봤다.
작성한 프로그램에서 버그나 어떤 문제가 생기면 프로그램은 패닉에 빠진다. 몇 가지 예시로는
unwrap
할 때expect
를 사용할 때fn main() {
panic!("The Panic..")
}
panic!
매크로 안의 메시지와 함께 패닉이 발생한 지점을 알려준다. main.rs
파일의 두번째 줄에서 패닉이 발생했다.
또 한 backtrace
를 사용할 수 있음을 알려준다.
RUST_BACKTRACE
환경 변수를 설정하면 러스트가 해당 지점의 스택을 같이 전달해준다.
우선 Cargo.toml
에 dependencies에 backtrace를 추가하고 프로젝트 터미널에
RUST_BACKTRACE=1 cargo run
을 실행하면
$ RUST_BACKTRACE=1 cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target/debug/pr`
thread 'main' panicked at 'The Panic..', src/main.rs:2:5
stack backtrace:
0: rust_begin_unwind
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5
1: core::panicking::panic_fmt
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14
2: pr::main
at ./src/main.rs:2:5
3: core::ops::function::FnOnce::call_once
at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/ops/function.rs:250:5
요렇게 나오게 된다.
Result 타입은 실패 할 수도 있는 가능성에 대해 나타낸다. 예를 들어 어떤 파일을 여는데 해당 파일이 존재하지 않을 경우 패닉을 발생시켜 프로세스를 멈추는대신 파일을 새로 만드는것이 더욱 깔끔할지도 모른다.
Rust에서 Result는 열거형으로 OK
와 Err
라는 두 개의 variant를 가지고 있다.
enum Result<T, E> {
Ok(T),
Err(E),
}
Ok(T)
는 성공했을때 나타내는 값을 반환하고, Err(E)
는 에러를 나타내고 에러 값을 포함하는 값을 반환한다.
use std::fs::File;
fn main() {
let my_file = File::open("hello.txt");
}
File::open
은 아래와 같이 정의되어 있다.
pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
Result를 반환하는 것을 확인했으니, 이는 성공할 수도 실패할 수도 있다는 것을 알게되었다.
파일이 존재하지 않거나 파일에 접근할 권한이 없거나 등 다양한 상황에서, 위 함수를 통해 성공했는지 혹은 실패했는지 여부를 알려주면서 동시에 파일 핸들링이나 에러 핸들링을 할 수 있다.
만약 hello.txt
파일이 존재한다면 my_life
변수에는 Ok(T)
의 인스턴스가 들어갈 것이고 실패할 경우는 Err(e)
의 인스턴스가 될 것이다.
다시 처음으로 돌아와서, 파일이 없어서 실패한 것이라면 새로운 파일을 생성하고, 그것이 아니라면 패닉과 함께 에러 메시지를 리턴하고 싶다면,
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let my_file = File::open("hello.txt");
let my_file = match my_file {
Ok(file) => file,
Err(ref error) if error.kind() == ErrorKind::NotFound => {
match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => {
panic!(
"Tried to create file but there was a problem: {:?}",
e
)
},
}
},
Err(error) => {
panic!(
"There was a problem opening the file: {:?}",
error
)
},
};
}
실행전과 실행후의 차이, hello.txt
파일이 없으면 새로 생성하기까지 완료되었다.