Peter
Peter

Reputation: 707

Why is `return` necessary in `match` arm when using `Result` in `main`?

I am reading Rust by Example book. In this example removing return in Err(e) => return Err(e) causes an error: expected `i32`, found enum `Result`` . Why is that?

What is the difference between Err(e) => return Err(e) and Err(e) => Err(e)?

Here is the code from the example:

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let number_str = "10";
    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => return Err(e),
    };
    println!("{}", number);
    Ok(())
}

Upvotes: 1

Views: 2562

Answers (2)

cameron1024
cameron1024

Reputation: 10196

All arms of a match have to have "compatible" types. This either mean they all have the same type:

fn is_some<T>(opt: &Option<T>) -> bool {
  match opt {
    // both arms have type bool
    Some(_) => true,
    None => false,
  }
}

or some of the branches need to direct control flow away from the match in some way.

The main rule to keep in your head is that every variable in Rust needs a single type (ignoring variance w.r.t. lifetimes). In your case, if you didn't have the return keyword, what would be the type of number?

If the parse succeeds, number would be an i32. If it fails, it would be an Err(ParseIntError). This isn't allowed, so you get a compile error.

However, if you return Err(e), number will always be an i32 (since return prevents the rest of the function running, so number doesn't need a type).

A similar thing applies to other control-flow keywords (e.g. continue, break, ...), as well as things that are guaranteed to not return, like panic!() (look up the Never/! type for more info)

Upvotes: 3

Schwern
Schwern

Reputation: 165386

    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => return Err(e),
    };

This says if number_str.parse::<i32>() returns an Ok to set number to number, an i32. If it returns an Err to immediately return Err(e), which is a Result, from main, number is not set.

That's fine because number can only be an i32 and main does return a Result.

    let number = match number_str.parse::<i32>() {
        Ok(number)  => number,
        Err(e) => Err(e),
    };

This says if number_str.parse::<i32>() returns an Ok to set number to number, an i32, same as before. If it returns an Err to set number to Err(e), which is a Result.

number cannot be both an i32 and a Result, so you get a compiler error.

Upvotes: 5

Related Questions