Propagating Errors with ?

The try-operator ? is used to return errors to the caller. It lets you turn the common

match some_expression { Ok(value) => value, Err(err) => return Err(err), }

into the much simpler

some_expression?

We can use this to simplify our error handing code:

  1. use std::fs;
  2. use std::io::{self, Read};
  3. fn read_username(path: &str) -> Result<String, io::Error> {
  4. let username_file_result = fs::File::open(path);
  5. let mut username_file = match username_file_result {
  6. Ok(file) => file,
  7. Err(e) => return Err(e),
  8. };
  9. let mut username = String::new();
  10. match username_file.read_to_string(&mut username) {
  11. Ok(_) => Ok(username),
  12. Err(e) => Err(e),
  13. }
  14. }
  15. fn main() {
  16. //fs::write("config.dat", "alice").unwrap();
  17. let username = read_username("config.dat");
  18. println!("username or error: {username:?}");
  19. }

Key points:

  • The username variable can be either Ok(string) or Err(error).
  • Use the fs::write call to test out the different scenarios: no file, empty file, file with username.