Rust Error handling Basic Error Reporting and Handling


Example

Result<T, E> is an enum type which has two variants: Ok(T) indicating successful execution with meaningful result of type T, and Err(E) indicating occurrence of an unexpected error during execution, described by a value of type E.

enum DateError {
    InvalidDay,
    InvalidMonth,
}

struct Date {
    day: u8,
    month: u8,
    year: i16,
}

fn validate(date: &Date) -> Result<(), DateError> {
    if date.month < 1 || date.month > 12 {
        Err(DateError::InvalidMonth)
    } else if date.day < 1 || date.day > 31 {
        Err(DateError::InvalidDay)
    } else {
        Ok(())
    }
}

fn add_days(date: Date, days: i32) -> Result<Date, DateError> {
    validate(&date)?; // notice `?` -- returns early on error
    // the date logic ...
    Ok(date)
}

Also see docs for more details on ? operator.

Standard library contains an Error trait which all error types are recommended to implement. An example implementation is given below.

use std::error::Error;
use std::fmt;

#[derive(Debug)]
enum DateError {
    InvalidDay(u8),
    InvalidMonth(u8),
}

impl fmt::Display for DateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &DateError::InvalidDay(day) => write!(f, "Day {} is outside range!", day),
            &DateError::InvalidMonth(month) => write!(f, "Month {} is outside range!", month),
        }
    }
}

impl Error for DateError {
    fn description(&self) -> &str {
        match self {
            &DateError::InvalidDay(_) => "Day is outside range!",
            &DateError::InvalidMonth(_) => "Month is outside range!",
        }
    }

    // cause method returns None by default
}

Note: Generally, Option<T> should not be used for reporting errors. Option<T> indicates an expected possibility of non-existence of a value and a single straightforward reason for it. In contrast, Result<T, E> is used to report unexpected errors during execution, and especially when there are multiple modes of failures to distinguish between them. Furthermore, Result<T, E> is only used as return values. (An old discussion.)