Error Handling in Rust – Error are a fact of life in Software.

Reading Time: 4 minutes

Hello Readers!! Again I am here with an exciting topic that is Error Handling. As we know errors are things that no one wants in their program. So lets see what are Errors and how we can handle them . An error is basically an unexpected behaviour or event that may lead a program to produce undesired output or terminate abruptly.

We can try to find and analyze parts of the program that can cause errors. Once we found those parts then we can define how those parts should behave if they encounter an error. 

This process of finding and defining cases for a particular block of code is what we call Error Handling.

One thing we should keep in mind that we cannot completely get rid of errors but we can try to reduce their effect on our program.

Types of Errors

Rust groups errors into two major categories:

  • Recoverable Error
  • Unrecoverable Error

Most languages don’t distinguish between these two kinds of errors and handle both in the same way, using mechanisms such as exceptions.

Rust doesn’t have exceptions. Instead, it has the type Result<T, E> for recoverable errors and the panic! macro that stops execution when the program encounters an unrecoverable error. 

Unrecoverable Errors

Unrecoverable errors are those errors which as the name suggests can not be handled by a programmer.

When any unrecoverable error occurs the end result is the program quits (terminates). The complete process is the first panic! macro is fired then the error message is printed along with the location of it and finally, the program is terminated. It mostly arises due to the bugs left by the programmer in the code.

Example 1:

  • In this example, we will call panic! macro.
  • It will show our error message and the complete stack trace(location, message).
  • After this, it unwinds and cleans up the stack, and then quit(terminate the program).
fn main() {

// this will result in unrecoverable error
panic!("Here we call panic macro");
}

This will give you following Unrecoverable Error:

thread 'main' panicked at 'Here we call panic macro', src\main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\unrecoverableErrors.exe` (exit code: 101)

Example 2:

  • In this program, we will define one arr array which will consist of four strings.
  • Now we will try to print 5 element in the array and because the length is 4 [0-3] and we are looking for 5th index than it will trigger panic! macro.
  • After this, it will print the error message, location, and stack trace.
fn main() {
let arr=["cp","algo","ds","FAANG"];

// index 5 does not exist
// than it will trigger panic! macro
println!("{}", arr[5]);
}

This will give you the following Error:

error: this operation will panic at runtime
 --> src\main.rs:5:20
  |
5 |     println!("{}", arr[5]);
  |                    ^^^^^^ index out of bounds: the length is 4 but the index is 5
  |
  = note: `#[deny(unconditional_panic)]` on by default

These were unrecoverable errors which we can not be handled explicitly. So lets see what are recoverable Errors.

Recoverable Errors

Recoverable errors are those that do not cause the program to terminate abruptly.

Example- When we try to fetch a file that is not present or we do not have permission to open it.

Rust uses a data type Result <R,T> to handle recoverable errors and panic! macro to stop the execution of the program in case of unrecoverable errors. 

Result<T,E> is an enum data type with two variants OK and Err which is defined something like this:-

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

T and E are generic type parameters where T represents the type of value that will be returned in a success case within the Ok variant, 

and E represents the type of error that will be returned in a failure case within the Err variant.

Example 1:

use std::fs::File;

fn main() {
let file1 = File::open(“abc.txt");
	println!("{:?}",file1);
}

OUTPUT:

Err(Os { code: 2, kind: NotFound, message: "No such file or directory" })

This Error can be handled in the way given below:

use std::fs::File;
fn main() {
// file doesn't exist
let file1 = File::open("abc.txt");
match file1 {
	Ok(file)=> {
		println!("file found {:?}",file);
	},
	Err(_error)=> {
		println!("file not found \n");
	}
    }
}

OUTPUT:

file not found

So this is how we can handle the Errors in Rust. In the next blog we will see some more concepts Error Handling in Rust.

Please stay connected for more details. Thanks for Reading!!

If you want to read more content like this?  Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.


Knoldus-blog-footer-image

Written by 

Ayushi is a Software Developer having more than 1.5 year of experience in RUST. Her practice area is Rust and Go. She loves to solve daily coding challenges.