Evian
Evian

Reputation: 1205

Rust -- How to handle error precisely and gracefully?

Sorry for naming this a so ambiguous title, but I can't come up with a better one.

The read_dir() method defined in std::fs returns instances of io::Result<DirEntry>, which is the alias of Result<DirEntry, io::Error>. When the caller does not exist on file system, it returns the error.

Now my code is

dir_a.read_dir();
dir_b.read_dir();
dir_c.read_dir();

And dir_a, dir_b, dir_c all may not exist. So these three statements may return the same io::Error, but for my program, dir_a, dir_b and dir_c have different meaning, where I want to handle the error for each one respectively.

So I defined my own enum MyError as

enum MyError {
    Dir_a_not_exist,
    Dir_b_not_exist,
    Dir_c_not_exist,
}

How can I transform the same io::Error to my different three MyError?

My ugly way is to

match dir_a.read_dir() {
    Ok => match dir_b.read_dir() {
              Ok => match dir_c.read_dir() {
                        Ok => { /* do something */ },
                        Err => return MyError::Dir_c_not_exist,
                    },
              Err => return MyError::Dir_b_not_exist,
          },
    Err => return MyError::Dir_a_not_exist,
};

Is there any graceful way I can handle this?

Upvotes: 0

Views: 226

Answers (1)

Benjamin Lindley
Benjamin Lindley

Reputation: 103761

Result has a function called or, that allows you to forward the result if it's Ok, or transform it if it's an error. With that, you can do something like this:

fn foo(dir_a: &Path, dir_b: &Path, dir_c: &Path) -> Result<(), MyError> {
    dir_a.read_dir().or(Err(MyError::DirAnotExist))?;
    dir_b.read_dir().or(Err(MyError::DirBnotExist))?;
    dir_c.read_dir().or(Err(MyError::DirCnotExist))?;

    /* do something */

    Ok(())
}

Upvotes: 4

Related Questions