Handling errors from Result mixed with Option

Hi,

I'm trying to build a rust program. Part of it involves a function that:

  • Read a directory and collects the files paths into a vector => Could lead to some error if it can't read the directory
  • Chooses a random file from the list => Could be none, if the directory is empty
  • Reads the content of the file to a string => Could lead to an error if it Can´t read the file

Currently it works with unwraping:

fn template(dir: &Path) -> Result<String, io::Error> {
    let mut rng = thread_rng();
    let files = fs::read_dir(dir).unwrap();
    let file = files.choose(&mut rng).unwrap().unwrap();
    let text = fs::read_to_string(file.path());
    return text
}

I even need to call unwrap twice at some point :confused:
I've tried a few different approaches to remove these unwraps but couldn't get it to work, anyone can help me or point in the right directon?

You can use or_else to convert an Option to a Result. Then your code becomes:

fn template(dir: &Path) -> Result<String, io::Error> {
    let mut rng = thread_rng();
    let files = fs::read_dir(dir)?;
    let file = files.choose(&mut rng).or_else(|| io::Error::new(ErrorKind::NotFound, "directory is empty"))??;
    let text = fs::read_to_string(file.path())?;
    Ok(text)
}
6 Likes

Thank you. Much simpler than the solution I had so far:

fn template(dir: &Path) ->  Result<String, io::Error> {
    let files = fs::read_dir(dir)?
        .map(|res| res.map(|e| e.path()))
        .collect::<Result<Vec<_>, io::Error>>()?;
    let file = files
        .choose(&mut rng)
        .ok_or_else(|| io::Error::new(ErrorKind::NotFound, "Directory is empty"))?;
    let text = fs::read_to_string(file)?;
    Ok(text)
}

No need to collect into a vector, and the nested maps were really bugging me. I got it from an example of the read_dir docs but I can't quite understand it.

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.