Sage-Code Laboratory
index<--

Rust Errors

Rust groups errors into two major categories: recoverable and unrecoverable errors. First are situations in which it's reasonable to report the problem and retry or continue. Unrecoverable errors are always symptoms of bugs. In this case, program should stop execution immediately.!

Panic

We use the panic macro to create an unrecoverable error and stop program execution.

fn main() {
    panic!("crash and burn");
}

Result

We do not have a try block like in Java. Instead we use a special enum that is "Result". In Rust we do not have a classic approach but a more exotic one. To understand how is done you must unintended the Result type the match patterns and the new operator "?" used for error propagation.

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Note: Result is an enumeration and a generic type.

In Rust library some functions may return a Result. To use these functions we need to handle the errors. We may decide to continue the program or to create a meaningful message and exit the program. Or we may decide to do nothing and let the error propagate out of current scope.

Observe that Result start with capital letter (types are PascalCased). Normally any function return a result but only some functions return a Result. That is a difference between the two. To function that return a Result may be successful but may be in error that need to be handled.

We handle the errors using pattern matching we have just learned recently.

Here is how is done:

use std::fs::File;

fn main() {
    // we try to open the file and capture the result in handler f of type Result
    let f = File::open("hello.txt");

    // now we look at f that is of type result and handle the error 
    let f = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("There was a problem opening the file: {:?}", error)
        },
    }; // end match
} //end main

It looks very complicated? Read the comments in the example maybe this will help. The good news is there are some tricks already implemented that makes the program much more easy to read and follow. Most of the time we do not handle the errors using match but using these tricks I will explain next:

The tricks

First trick is to do nothing at all by propagating the error to next level. This is using operator "?". In the case of error we do not know what to do so we put the question mark and continue programming. If an error is present this will be propagated and program will probably stop working.

use std::fs::File;
use std::io;

fn main() -> io::Result<()> {
    let f = File::open("hello.txt")?;
    Ok(())
}

Do you see the question mark after the expression open()?. That all to propagate an error.

Shortcuts

The second trick is more neat. We use a built-in helper method for Result type. This method can be call with dot operator "." after the expression that can return a type Result. We just mention .expect("error message") or even better we use .unwrap(). That's it a simple function call will resolve our expected error issue. Now the error is "handled"

Using expect:

use std::fs::File;

fn main() {
    let f = File::open("hello.txt").expect("Error: File not found!");
}

Using unwrap:

use std::fs::File;

fn main() {
    let f = File::open("hello.txt").unwrap();
}

To be continued ...


Go back to: Rust Tutorial