panic
대부분 프로그래밍 언어에서는 잘못된 코드가 있거나 어떤 오작동이 일어나면 '에러'라는 개념을 사용합니다.
Rust는 매우 보안이 신경을 쓰는 편이어서 조금의 실수라도 있으면 다 잡아서 실질적으로 파일을 만들지도 못하게 합니다.
프로그램을 만드는데 다음 과정을 거칩니다.
- 코드를 이진수로 바꾸기 (컴파일)
- 파일에 저장하기
- 파일 실행하기 :::
그래서 에러가 있으면 컴파일도 하지 못하는데요 이 과정에서 생기는 문제를 'panic'이라고 합니다.
나만의 panic은 panic!()
을 통해 만들 수 있습니다.
Backtrace
backtrace란 panic이 생긴 이유를 알아보는 과정입니다.
fn main() {
let v = vec![1, 2, 3];
v[99];
}
위의 코드를 실행하면 다음과 같은 결과가 출력됩니다.
$ cargo run
Compiling panic v0.1.0 (file:///projects/panic)
Finished dev [unoptimized + debuginfo] target(s) in 0.27s
Running `target/debug/panic`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
위의 코드에서 RUST_BACKTRACe=1
이라는 환경 변수를 사용해서 backtrace를 출력합니다.
RUST_BACKTRACE=1 cargo run
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
stack backtrace:
0: rust_begin_unwind
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/std/src/panicking.rs:483
1: core::panicking::panic_fmt
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:85
2: core::panicking::panic_bounds_check
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/panicking.rs:62
3: <usize as core::slice::index::SliceIndex<[T]>>::index
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/slice/index.rs:255
4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/slice/index.rs:15
5: <alloc::vec::Vec<T> as core::ops::index::Index<I>>::index
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/alloc/src/vec.rs:1982
6: panic::main
at ./src/main.rs:4
7: core::ops::function::FnOnce::call_once
at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/core/src/ops/function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
넘어갈 수 있는 에러
에러 하나로 인해 코드 전체를 실행할 수 없을 때가 있습니다.
하지만 rust에서는 일부 중요한 에러들을 다루어서 전체적인 코드에 지장이 없게 만들 수 있습니다.
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
println!("Hello World");
}
위 코드에서 에러가 생기면 다음 코드를 실행할 수 없습니다.
하지만 Ok()
와 Err()
를 사용하면 에러가 생겨도 넘어가서 다음 코드를 실행할 수 있습니다.
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
println!("Hello World")
}
다양한 에러 종류
에러에는 다양한 종류가 있습니다.
이는 Err(error) =>
안에서 에러의 종류에 따라 다양한 코드를 실행할 수 있습니다.
에러의 종류는 std::io::ErrorKind
를 통해 알 수 있습니다.
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!("Problem creating the file: {:?}", e),
},
other_error => {
panic!("Problem opening the file: {:?}", other_error)
}
},
};
}