RUST의 Error Type
Rust에서는 에러를 크게 두 가지 범주로 나누어 다룬다.
복구 가능한 에러(Recoverable Errors)와 복구 불가능한 에러(Unrecoverable Errors).
1. 복구 가능한 에러 (Recoverable Errors)
복구 가능한 에러는 일반적으로 프로그램의 실행을 중단시키지 않고 처리할 수 있는 에러를 말한다.
이러한 에러는 주로 예상 가능하며, 프로그램이 에러 상황을 감지하고 적절히 대응할 수 있다.
Rust에서는 Result<T, E> 타입을 사용하여 복구 가능한 에러를 처리한다.
예를들어 아래는 특정 파일을 열어보는 예제이다.
해당 파일이 없을때는 에러를 반환해준다.
use std::fs::File;
fn main() {
let file = File::open("rust_good.txt");
// 에러 핸들링 -> 여기서 에러가 발생한다고 해도 시스템이 종료되지 않음.
let file: Result<File, bool> = match file {
Ok(f) => Ok(f),
Err(e) => {
Err(false)
}
};
println!("{:?}", file);
}
2. 복구 불가능한 에러 (Unrecoverable Errors)
복구 불가능한 에러는 프로그램의 실행을 즉시 중단시키는 심각한 에러를 말한다.
이러한 에러는 주로 버그나 논리적 오류로 인해 발생하며, 일반적으로 복구할 수 없다.
아래 예제는 벡터에 범위를 벗어난 인덱스로 접근할 때 panic!이 발생하는 상황을 보여준다.
fn main() {
let v = vec![1, 2, 3];
// 벡터의 범위를 벗어난 접근
println!("Element at index 99: {}", v[99]);
}
Rust에서는 panic! 매크로를 사용하여 이러한 상황을 처리할수도 있고,
panic 상황을 강제로 발생시킬 수 있다.
panic! 매크로
이 매크로는 에러 메시지를 출력하고, 스택을 정리한 후 프로그램을 즉시 종료한다.
fn main() {
println!("hello");
panic!(" [ panic erruption ] ");
println!("bye");
}
unwrap()
Rust에서 unwrap 메서드는 Option 또는 Result 타입에 대해 사용되며,
이 타입들이 보유한 값에 직접 접근하고자 할 때 사용된다.
unwrap은 내부 값을 추출하지만, 만약 None이나 Err 상태라면 프로그램은 패닉(panic) 상태로 진입한다.
1) Option<T>에 대한 unwrap()
Option<T> 타입은 값이 있을 수도(Some(T)) 있고 없을 수도(None) 있다.
unwrap()을 사용하면 Some 내부의 값 T를 추출한다.
만약, Option이 None이라면 unwrap은 패닉을 일으킨다.
이는 값이 없음을 나타내며, unwrap은 이 상황을 처리할 수 없다.
fn main() {
let maybe_number = Some(10);
let just_number = maybe_number.unwrap(); // `Some` 상태이므로, 10을 추출한다.
println!("Number is {}", just_number);
}
unwrap은 간결하지만, 사용할 때 주의해야 한다.
None 또는 Err 상태에서 unwrap을 호출하면 프로그램이 패닉 상태로 진입하고,
이는 예상치 못한 종료를 초래할 수 있다.
따라서, unwrap 사용은 값이 반드시 존재한다는 것이 확실한 경우에만 권장된다.
2) Result<T, E>에 대한 unwrap()
Result<T, E> 타입은 성공(Ok(T))과 실패(Err(E))의 두 가지 상태를 나타낸다.
unwrap()을 사용하면 Ok 내부의 값 T를 추출한다.
만약 Result가 Err 상태라면, unwrap은 패닉을 일으킨다.
fn main() {
let maybe_error: Result<i32, &str> = Err("There was an error");
let error = maybe_error.unwrap(); // `Err` 상태이므로, 여기에서 패닉이 발생한다.
}
expect()
Rust에서 expect 메서드는 Option과 Result 타입에 사용되며, unwrap과 유사한 기능을 수행하지만,
에러 메시지를 사용자가 직접 제공할 수 있는 추가적인 기능을 가지고 있다.
expect는 내부 값을 추출하지만, 만약 Option이 None이거나 Result가 Err일 경우,
제공된 에러 메시지와 함께 프로그램이 패닉(panic) 상태로 진입한다.
1) Option<T>에 대한 expect
expect을 사용하여 Some 내부의 값 T를 추출할 수 있다.
Option이 None인 경우, expect는 제공된 메시지와 함께 패닉을 발생시킨다.
fn even_cheker(num: i32) -> Option<i32> {
if num%2 == 0 {
Some(num)
} else {
None
}
}
fn main() {
let maybe_number1 = even_cheker(2);
let maybe_number2 = even_cheker(3);
let just_number1 = maybe_number1.expect("No number found");// Some 값을 반환
println!("just_number1 is {}", just_number1);
let just_number2 = maybe_number2.expect("No number found");// None을 반환하므로 패닉
println!("just_number2 is {}", just_number2);
}
2) Result<T, E>에 대한 expect
expect을 사용하여 Ok 내부의 값 T를 추출할 수 있다.
Result가 Err 상태인 경우, expect는 제공된 메시지와 함께 패닉을 발생시킨다.
fn even_cheker(num: i32) -> Result<i32, &'static str> {
if num%2 == 0 {
Ok(num)
} else {
Err("this number is odd number.")
}
}
fn main() {
let maybe_number1 = even_cheker(2);
let maybe_number2 = even_cheker(3);
let just_number1 = maybe_number1.expect("No number found");// Ok 값을 반환
println!("just_number1 is {}", just_number1);
let just_number2 = maybe_number2.expect("No number found");// Err을 반환하므로 패닉
println!("just_number2 is {}", just_number2);
}
unwrap_or()
Rust에서 unwrap_or 메서드는 Option 타입에 사용되어,
Option이 None일 경우 제공된 기본 값을 반환한다.
unwrap_or는 Option이 Some을 감싸고 있는 경우 그 내부 값을 반환하고,
None일 경우 지정된 기본 값을 반환한다.
이는 Option 타입에서 값이 없는 경우를 안전하게 처리하는 데 유용하다.
fn main() {
let option_value = Some(10);
let default_value = 0;
// `option_value`가 `Some`이므로, 내부의 값인 10을 반환.
let result = option_value.unwrap_or(default_value);
println!("The result is {}", result);
let none_value: Option<i32> = None;
// `none_value`가 `None`이므로, 기본 값인 0을 반환.
let result = none_value.unwrap_or(default_value);
println!("The result is {}", result);
}
unwrap_or_else()
Rust에서 unwrap_or_else 메서드는 Option 타입에 사용되며,
Option이 None일 때 실행할 함수를 인자로 받는다.
unwrap_or_else는 Option이 Some 값을 감싸고 있으면 그 내부 값을 반환하고,
None일 경우 제공된 클로저(함수)를 실행하여 그 결과를 반환한다.
이 메서드는 None 상황에 대해 더 복잡한 로직을 실행하고 싶을 때 유용하다.
fn main() {
let option_value = Some(10);
// `option_value`가 `Some`이므로, 내부의 값인 10을 반환.
let result = option_value.unwrap_or_else(|| 0);
println!("The result is {}", result);
let none_value: Option<i32> = None;
// `none_value`가 `None`이므로, 클로저에서 제공된 값 20을 반환.
let result = none_value.unwrap_or_else(|| {
println!("Calculating default value...");
20 // 클로저에서 계산된 기본 값
});
println!("The result is {}", result);
}
Error 를 전파하는 방법
Rust에서 에러를 전파한다는 것은 함수가 에러를 직접 처리하지 않고
호출한 쪽으로 에러를 "넘긴다"는 의미이다.
이는 주로 ? 연산자를 사용하여 구현되며,
이를 통해 함수는 발생한 에러를 자신을 호출한 함수에게 반환한다.
에러 전파는 코드의 가독성을 높이고, 에러 처리 로직을 중복 작성하는 것을 방지하는 데 유용하다.
아래의 예제를 보자.
use std::fs::File;
use std::io::Error;
use std::io::Read;
fn read_username() -> Result<String, Error> {
let mut file = match File::open("rust_goods.txt") {
Ok(file) => file,
Err(e) => return Err(e)
};
let mut user_name = String::new();
match file.read_to_string(&mut user_name) {
Ok(_) => Ok(user_name),
Err(e) => Err(e)
}
}
fn main() {
let result = match read_username() {
Ok(res) => res,
Err(e) => {
println!("{:?}",e);
String::from("Empty String")
}
};
println!("result = {}", result);
}
위의 예제에서 read_username() 함수는 특정 파일을 찾은 다음,
해당 파일의 내용을 읽어서 반환해주는 기능을 담당한다.
위의 에러처리를 "?" 를 사용해서 처리하면 좀더 간결하게 코드를 작성할 수 있다.
use std::fs::File;
use std::io::Error;
use std::io::Read;
fn read_username() -> Result<String, Error> {
let mut file = File::open("rust_goods.txt")?;
let mut user_name = String::new();
file.read_to_string(&mut user_name)?;
Ok(user_name)
}
fn main() {
let result = match read_username() {
Ok(res) => res,
Err(e) => {
println!("{:?}",e);
String::from("Empty String")
}
};
println!("result = {}", result);
}
또한 아래와 같이 연달아서 "?" 표현을 사용할 수 있다.
use std::fs::File;
use std::io::Error;
use std::io::Read;
fn read_username() -> Result<String, Error> {
let mut user_name = String::new();
File::open("rust_good.txt")?.read_to_string(&mut user_name)?;
Ok(user_name)
}
fn main() {
let result = match read_username() {
Ok(res) => res,
Err(e) => {
println!("{:?}",e);
String::from("Empty String")
}
};
println!("result = {}", result);
}
'RUST' 카테고리의 다른 글
[RUST] 트레이트 (Traits) (0) | 2024.01.23 |
---|---|
[RUST] 제네릭 (Generics) (0) | 2024.01.22 |
[RUST] ENUM (0) | 2024.01.02 |
[RUST] 구조체(structure) (0) | 2023.12.29 |
[RUST] RUST 메모리 관리 규칙 - Slice (0) | 2023.12.28 |