[rust] Rust 언어의 에러 핸들링

Rust는 안정적이고 안전한 시스템 프로그래밍을 위한 언어로, 에러 핸들링에 대해 엄격한 접근 방식을 채택했습니다. 이번 포스트에서는 Rust에서의 에러 핸들링에 대해 알아보겠습니다.

Result 타입

Rust에서 함수가 에러를 반환할 수 있는 경우, Result 타입을 사용합니다. Result는 에러를 포함하는 Err나 성공한 값을 포함하는 Ok 중 하나를 가집니다. 함수가 Result를 반환하면, 호출하는 쪽에서 이를 확인하고 적절히 에러를 처리할 수 있습니다.

use std::fs::File;

fn read_file(file_path: &str) -> Result<String, std::io::Error> {
    let file = File::open(file_path)?;

    // 파일 읽기 로직
    // ...

    Ok(contents)
}

위 예제에서 read_file 함수는 Result를 반환하고, 파일을 열거나 에러가 발생할 경우 Err을 반환합니다.

에러 핸들링

Rust는 Result에 대한 처리를 강제하기 때문에, 개발자는 에러를 무시하거나 미루지 않고 항상 적절히 처리해야 합니다. 이는 프로그램이 예측할 수 없는 동작을 하지 않도록 보장합니다.

매칭(matching)을 통해 Result를 처리할 수 있습니다.

fn main() {
    let file_path = "example.txt";
    match read_file(file_path) {
        Ok(contents) => println!("File contents: {}", contents),
        Err(err) => eprintln!("Error reading file: {}", err),
    }
}

match 표현식을 사용하여 Result를 처리하였으며, OkErr의 경우를 각각 처리하고 있습니다.

실패를 발생시키는 커스텀 에러

개발자는 자체적인 에러 타입을 정의하고 실패하는 조건에 대해 해당 에러를 반환할 수 있습니다. 이를 통해 명확한 의미와 정보를 담은 에러를 사용할 수 있습니다.

enum CustomError {
    NotFound,
    AccessDenied,
    InvalidData,
    // ...
}

fn some_operation() -> Result<(), CustomError> {
    if condition1 {
        return Err(CustomError::NotFound);
    } else if condition2 {
        return Err(CustomError::AccessDenied);
    }
    Ok(())
}

매칭을 통해 각각의 커스텀 에러를 처리할 수 있으며, 호출하는 쪽에서 어떤 실패 상황이 발생했는지 명확하게 파악할 수 있습니다.

요약

Rust의 엄격한 에러 핸들링은 코드의 안정성을 높이고 예측할 수 있는 프로그래밍을 지원합니다. Result 타입을 통한 명시적인 에러 처리와 커스텀 에러 타입을 통한 실패 시의 정보 전달은 Rust의 에러 핸들링을 강력한 기능으로 만듭니다.

에러 처리를 통해 설명이 필요한 추가 정보나 경고를 제공할 수 있으므로, Rust 프로그램의 신뢰성을 높이는 데 큰 도움을 줍니다.

참고 자료