Introducing ?

Sometimes we just want the simplicity of unwrap without the possibility of
a panic. Until now, unwrap has forced us to nest deeper and deeper when
what we really wanted was to get the variable out. This is exactly the purpose of ?.

Upon finding an Err, there are two valid actions to take:

  1. panic! which we already decided to try to avoid if possible
  2. return because an Err means it cannot be handled

? is almost[^†] exactly equivalent to an unwrap which returns
instead of panics on Errs. Let’s see how we can simplify the earlier
example that used combinators:

  1. use std::num::ParseIntError;
  2. fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
  3. let first_number = first_number_str.parse::<i32>()?;
  4. let second_number = second_number_str.parse::<i32>()?;
  5. Ok(first_number * second_number)
  6. }
  7. fn print(result: Result<i32, ParseIntError>) {
  8. match result {
  9. Ok(n) => println!("n is {}", n),
  10. Err(e) => println!("Error: {}", e),
  11. }
  12. }
  13. fn main() {
  14. print(multiply("10", "2"));
  15. print(multiply("t", "2"));
  16. }

The try! macro

Before there was ?, the same functionality was achieved with the try! macro.
The ? operator is now recommended, but you may still find try! when looking
at older code. The same multiply function from the previous example
would look like this using try!:

  1. use std::num::ParseIntError;
  2. fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
  3. let first_number = try!(first_number_str.parse::<i32>());
  4. let second_number = try!(second_number_str.parse::<i32>());
  5. Ok(first_number * second_number)
  6. }
  7. fn print(result: Result<i32, ParseIntError>) {
  8. match result {
  9. Ok(n) => println!("n is {}", n),
  10. Err(e) => println!("Error: {}", e),
  11. }
  12. }
  13. fn main() {
  14. print(multiply("10", "2"));
  15. print(multiply("t", "2"));
  16. }

[^†]: See re-enter ? for more details.