Getting a value from `Option<T>` if it is `Some(T)`, or from `Result<T, E>` if it is `None`

I want to get a value from Option<T> if it is Some(T), or from Result<T, E> if it is None.

Currently, I'm using a temporary struct and passing it to Option::ok_or to convert Option<T> to Result<T, E> as follows.

fn run_app(db_path: Option<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
    struct TempError;

    let db_path: PathBuf = db_path
        // Convert Option<PathBuf> to Result<PathBuf, TempError>.
        .ok_or(TempError)
        // Convert Result<PathBuf, TempError> to Result<PathBuf, my_app::InvalidEnvVarError>.
        // Return from this function if it is Err(my_app::InvalidEnvVarError).
        .or_else(|_| database_path_from_env())?;

    // Now db_path is PathBuf.

    // Open and process the database
    // ...

    Ok(())
}

fn database_path_from_env() -> Result<PathBuf, my_app::InvalidEnvVarError> {
    std::env::var("MY_APP_DATABASE")
        .map(PathBuf::from)
        .map_err(|_| my_app::InvalidEnvVarError)
}

Is there any way to achieve this in a more straightforward way without using a temporary struct?

This approach should work

let db_path: PathBuf = db_path.map(Ok).unwrap_or_else(database_path_from_env)?;

( edit: or shorter db_path.map_or_else(database_path_from_env, Ok)? )

Of course maximal clarity would probably just come from a simple match, despite the need to add another local variable name for the Some case.

let db_path: PathBuf = match db_path {
    Some(p) => p,
    None => database_path_from_env()?,
};
(Small afterthought on the naming of β€œp”)

Since it’s used only very locally, a single-letter name should be fine. And it spares the burden (to the writer and the reader) to come up with any meaningful new name. If no meaningful new name is to be invented, I believe using a short generically-named variable such as p looks better than the alternative of re-using the db_path name, because that becomes quite repetitive, i.e. better than this:

let db_path: PathBuf = match db_path {
    Some(db_path) => db_path,
    None => database_path_from_env()?,
};
4 Likes

Thank you so much. I was thinking too complicated. I will use a simple match expression.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.