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