Error Handling in Rust

There are a lot of things to love about Rust, not least of which are its excellent documentation and package handler (Cargo). But I also really like the error handling.

In Rust, you can choose to handle the error via having the program panic (which will abort the entire program), but this is generally considered something best avoided – especially if you are writing a program that other people will be using.

if n < 1 || n > 10 {
        panic!("Invalid number: {}", n);
    }

For example, if you had this in your code, and you passed in a number lower than n or greater than 10, you would not get a very good error message and it would be annoying.

An exception would be if the error is raised by something that should not happen and therefore indicating an actual bug in the program (and not simply the user typing the wrong thing, etc). In this case, you would want your program to panic and stop everything – because there is something way wrong that you didn’t foresee (and so probably could not have written a specific case for it).

You can unwrap something, which will either return the result of a computation or panic. But this, of course, runs into a lot of the same annoying things as panic.

You can also specify that, if you run into an error, for the program to simply continue. For example:

fn main() {
    println!("Guess the number!");
    println!("Enter your guess:");

    let secret_number = rand::thread_rng().gen_range(1, 101);
    
    loop {
        let mut guess = String::new();

        io::stdin().read_line(&mut guess)
        .expect("Failed to read input");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        println!("You guessed {}", guess);

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Higher!"),
            Ordering::Greater => println!("Lower!"),
            Ordering::Equal => {
                println!("You Win!");
                break;    
            }
        }
    }
}

If the person types in something that is a number, then it will be compared to the randomly generated number and told whether they have won or not. But if the person types in something that is not a number, then the the program will continue and the rest of the loop will simply skip and then ask the user to enter another number.

And there are many more ways to handle errors in Rust. You can write error messages for what happens when no arguments were passed when they were expected, or to display a different error if the argument fails to parse (and therefore is not the appropriate type), or to simply proceed as normal if everything checks out:

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    argv.nth(1)
        .ok_or("Please give at least one argument".to_owned())
        .and_then(|arg| arg.parse::<i32>().map_err(|err| err.to_string()))
        .map(|n| 2 * n)
}

fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {}", err),
    }
}

And there are many more ways to write helpful error messages and to handle the errors in such a way that your program behaves the way it should (which includes panic-ing when needed). This is just another part of what makes Rust so powerful and such a pleasure to work with.

Author: Steen

Steen is a nerdy biologist who spends a lot of time trying to cultivate Chloroflexi, who also likes to draw comics, play video games, and climb.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.