Rust lang series episode #19 — error handling (#rust-series)

in rust-series •  8 years ago  (edited)

Hello everyone, new episode of rust series is here, today we will discuss error handling in Rust. Proper error handling is key aspect for successful code in any programming language. Rust uses return values for error handling (in spite of languages intensively using exception). Let's start with some basics.

panic!

Panic macro terminates thread and report message. As we are in main thread, program is terminated.

fn main() {
    fn negate_one_digit(digit: i32) -> i32 {
        if digit < -9 || digit > 9 {
            panic!("Invalid argument, number must be between -9..9");
        }
        digit * (-1)
    }

    let result = negate_one_digit(10);
    println!("{}",result);

}

# output
thread 'main' panicked at 'Invalid argument, number must be between -9..9',    

Wrapped result

It's common to "wrap" return values in Rust into something like Option or Result

First check these enums

enum Option<T> {
    None,
    Some(T),
}

Option enum express possibility of absence (with None).

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

Result enum express possibility of error (with Err(E))

Unwrapping

Unwrapping is getting result if there is some (for Option) or if there is no error (for Result). Otherwise it calls panic!.

Check this for Option

impl<T> Option<T> {
    fn unwrap(self) -> T {
        match self {
            Option::Some(val) => val,
            Option::None =>
              panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}

And this for Result

impl<T, E: ::std::fmt::Debug> Result<T, E> {
    fn unwrap(self) -> T {
        match self {
            Result::Ok(val) => val,
            Result::Err(err) =>
              panic!("called `Result::unwrap()` on an `Err` value: {:?}", err),
        }
    }
}

Using Option

fn negate_one_digit(digit: i32) -> Option<i32> {

    let res : Option<i32>;
    if digit < -9 || digit > 9 {
        return None;
    }
    Some(digit * (-1))
}


fn main() {
    let res = negate_one_digit(9).unwrap();
    println!("{:?}", res );
    let res = negate_one_digit(10).unwrap();
}

# output
-9
error: thread panicked

Using Result

Now we implement similar function with using Result as return value

static CODE_OUT_OF_RANGE: i32 = 1;

fn negate_one_digit(digit: i32) -> Result<i32, i32> {

    let res : Result<i32, String>;
    if digit < -9 || digit > 9 {
        return Err(CODE_OUT_OF_RANGE);
    }
    Ok(digit * (-1))
}


fn main() {
    let res = negate_one_digit(9).unwrap();
    println!("{:?}", res );
    let res = negate_one_digit(10).unwrap();
}

# output
-9
error: thread panicked

unwrap_or

unwrap() means give me a result or if there is an error or no result then panic.
unwrap_or() means give me a result if there is an error or no result then return some predefined value;
Let's rewrite previous chapter with that

fn main() {
  let res = negate_one_digit(9).unwrap_or(0);
  println!("{:?}", res );
  let res = negate_one_digit(10).unwrap_or(0);
  println!("{:?}", res );
}

# output
-9
0

Now if there is a problem we will get neutral value 0.

Avoiding panicking with a better way

Easy approach is to match result and match the result and then perform custom action.

fn evaluate_res(res: Result<i32,i32>) {
    match res {
        Ok(value) => println!("{}", value),
        Err(err) => println!("ERROR_CODE:{}", err)
    }
}

fn main() {
    let res = negate_one_digit(9);
    evaluate_res(res);
    let res = negate_one_digit(10);
    evaluate_res(res);
}

# output

Error types

You can defined your own error types or codes as in previous piece of code but there are also standard ways like std::error:Error trait.

use std::fmt::{Debug, Display};

trait Error: Debug + Display {
  /// A short description of the error.
  fn description(&self) -> &str;

  /// The lower level cause of this error, if any.
  fn cause(&self) -> Option<&Error> { None }
}

There is more to error handling and we will return to this topic in the future but for now it's good to have some basics.

Postfix

That's all for now, thank you for your appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). May Jesus bless your programming skills, use them wisely and see you next time.

Meanwhile you can also check the official documentation for more details if you wish.

#rust-series
#rust-lang
#rust

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!