9장. 에러 처리

Gillilab - TechLog·2024년 11월 17일

Rust

목록 보기
10/21

9장. 에러 처리

Rust는 안전하고 신뢰할 수 있는 소프트웨어를 작성하기 위해 강력한 에러 처리 메커니즘을 제공합니다. Rust의 에러 처리는 크게 두 가지로 나뉩니다: 패닉(panic)과 Result 타입을 이용한 에러 처리입니다.

패닉 (Panic)

패닉은 프로그램이 복구할 수 없는 에러가 발생했을 때 사용됩니다. 패닉이 발생하면 프로그램은 즉시 중단되고 스택 트레이스를 출력합니다. 패닉은 주로 심각한 버그나 논리적 오류가 발생했을 때 사용됩니다.

패닉 예제

fn main() {
    let v = vec![1, 2, 3];

    // 존재하지 않는 인덱스에 접근하여 패닉 발생
    v[99];
}

위 예제에서 벡터의 존재하지 않는 인덱스에 접근하면 패닉이 발생합니다.

Result 타입

Rust의 Result 타입은 복구 가능한 에러를 처리하는 데 사용됩니다. Result 타입은 두 가지 변형을 가집니다: Ok(T)Err(E). Ok(T)는 성공적인 결과를 나타내고, Err(E)는 에러를 나타냅니다.

Result 타입 예제

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut file = File::open("hello.txt")?;
    let mut username = String::new();
    file.read_to_string(&mut username)?;
    Ok(username)
}

fn main() {
    match read_username_from_file() {
        Ok(username) => println!("Username: {}", username),
        Err(e) => println!("Error reading file: {}", e),
    }
}

위 예제에서 File::openfile.read_to_string 함수는 Result 타입을 반환합니다. ? 연산자는 에러가 발생하면 해당 에러를 호출자에게 반환하고, 그렇지 않으면 값을 언패킹합니다.

에러 전파

에러 전파는 함수가 에러를 처리하지 않고 호출자에게 전달하는 것을 의미합니다. ? 연산자를 사용하여 에러를 쉽게 전파할 수 있습니다.

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut file = File::open("hello.txt")?;
    let mut username = String::new();
    file.read_to_string(&mut username)?;
    Ok(username)
}

위 예제에서 ? 연산자는 에러가 발생하면 해당 에러를 호출자에게 반환합니다.

커스텀 에러 타입

Rust에서는 커스텀 에러 타입을 정의하여 더 구체적인 에러 처리를 할 수 있습니다.

use std::fmt;

#[derive(Debug)]
enum CustomError {
    NotFound,
    PermissionDenied,
}

impl fmt::Display for CustomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CustomError::NotFound => write!(f, "Not Found"),
            CustomError::PermissionDenied => write!(f, "Permission Denied"),
        }
    }
}

fn get_error(is_error: bool) -> Result<(), CustomError> {
    if is_error {
        Err(CustomError::NotFound)
    } else {
        Ok(())
    }
}

fn main() {
    match get_error(true) {
        Ok(_) => println!("No error"),
        Err(e) => println!("Error: {}", e),
    }
}

위 예제에서 CustomError 열거형을 정의하고, fmt::Display 트레이트를 구현하여 에러 메시지를 출력합니다.

에러 처리 요약

  • panic! 매크로

    • 예제: panic!("문제가 발생했습니다!"); // 프로그램이 중단되고 에러 메시지가 출력됩니다.
  • Result<T, E>

    • Result 열거형

      • 예제: let result: Result<i32, &str> = Ok(10); // 성공적인 결과를 나타냅니다.
    • match로 Result 처리

      • 예제:
        match result {
            Ok(value) => println!("값: {}", value),
            Err(e) => println!("에러: {}", e),
        }
    • 연산자 ?

      • 예제:

        fn divide(a: i32, b: i32) -> Result<i32, String> {
            if b == 0 {
                return Err("0으로 나눌 수 없습니다.".to_string());
            }
            Ok(a / b)
        }
        
        let result = divide(10, 0)?;
        println!("결과: {}", result);
  • 에러 전파

    • 예제:
      fn read_file() -> Result<String, std::io::Error> {
          let content = std::fs::read_to_string("파일.txt")?;
          Ok(content)
      }
  • 사용자 정의 에러 타입

    • 예제:

      #[derive(Debug)]
      enum MyError {
          NotFound,
          PermissionDenied,
      }
      
      fn do_something() -> Result<(), MyError> {
          Err(MyError::NotFound)
      }

Rust의 에러 처리 메커니즘을 사용하면 안전하고 신뢰할 수 있는 소프트웨어를 작성할 수 있습니다. 패닉은 복구할 수 없는 에러에 사용하고, Result 타입은 복구 가능한 에러에 사용하여 프로그램의 안정성을 높일 수 있습니다.

0개의 댓글