Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Why does Rust have both Result and Option types – how do I know which one to use?

Great question!

An Option represents cases where the absence of a value is still a valid response. It's similar to null in many languages (but you don't get to ignore it or de-reference a null and ruin your afternoon).

For example:

#![allow(unused)]
fn main() {
fn get_user(user_id: UserId) -> Option<User> {
    if user_exists {
        Some(user)
    } else {
        None
    }
}
}

The non-existence of a user with that ID isn't really an error (depending upon your logic). It's an absence of data.

Whereas this is an error:

#![allow(unused)]
fn main() {
fn load_user_from_database(user_id: UserId) -> Result<User, DbError> {
    return Err(DbError::DatabaseServerOnFire)
}
}

An error - a result - tells you if the operation succeeded, and if not, why not. Requesting a record from a database, but the connection fails? That's an error. Requesting a record from a database, but it doesn't exist? That's usually an Option.

As a result, it's not at all uncommon to express this as:

#![allow(unused)]
fn main() {
fn get_user(user: UserId) -> Result<Option<User>, DbError> { .. }
}

It's all about making intent really explicit, and making sure that you are handling different cases appropriately.