Skip to content

Error handling

Different languages have different ways to handle errors. Javascript, for example, has the concept of try catch blocks

try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log("File content:", data);
} catch (err) {
console.error("Error reading the file:", err);
}

The reason we put the code inside a try catch block is that reading a file is unpredictable. The file might not exist, the file might be locked by another process, and hence there is a possibility of this code throwing an error

The same is true for a rust program trying to access a file. But the way rust does error handling is slightly different

Result Enum

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

If you look at the code above, it is an enum (with generic types)

This enum is what a function can return/returns when it has a possibility of throwing an error

For example

use std::fs::File;
fn main() {
let greeting_file_result = fs::read_to_string("hello.txt");
}

Notice the type of greeting_file_result in VSCode

It returns an enum that looks as follows. It’s an enum with the Ok variant having a string value and Err variant having an Error value

enum Result{
Ok(String),
Err(Error),
}

Complete code

use std::fs;
fn main() {
let greeting_file_result = fs::read_to_string("hello.txt");
match greeting_file_result {
Ok(file_content) => {
println!("File read successfully: {:?}", file_content);
},
Err(error) => {
println!("Failed to read file: {:?}", error);
}
}
}

Incase you write a function yourself, you can also return a Result from it. As the name suggests, Result holds the result of a function call that might lead to an error.

Unwraps

Incase you are ok with runtime errors (crashing the process while it runs if an error happens), then you can unwrap a Result

use std::fs;
fn main() {
let greeting_file_result = fs::read_to_string("hello.txt");
print!("{}", greeting_file_result.unwrap());
}

Returning a custom error

use core::fmt;
use std::{fmt::{Debug, Formatter}, fs};
pub struct FileReadError {
}
fn main() {
let contents = read_file("hello.txt".to_string());
match contents {
Ok(file_content) => {
println!("File content: {}", file_content);
},
Err(error) => {
println!("Error reading file: {:?}", error);
}
}
}
fn read_file(file_path: String) -> Result<String, FileReadError> {
let greeting_file_result = fs::read_to_string("hello.txt");
match greeting_file_result {
Ok(file_content) => {
Ok(file_content)
},
Err(error) => {
let err = FileReadError {};
Err(err)
}
}
}