1# Early returns
2
3In the previous example, we explicitly handled the errors using combinators.
4Another way to deal with this case analysis is to use a combination of
5`match` statements and *early returns*.
6
7That is, we can simply stop executing the function and return the error if
8one occurs. For some, this form of code can be easier to both read and
9write. Consider this version of the previous example, rewritten using early returns:
10
11```rust,editable
12use std::num::ParseIntError;
13
14fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
15    let first_number = match first_number_str.parse::<i32>() {
16        Ok(first_number)  => first_number,
17        Err(e) => return Err(e),
18    };
19
20    let second_number = match second_number_str.parse::<i32>() {
21        Ok(second_number)  => second_number,
22        Err(e) => return Err(e),
23    };
24
25    Ok(first_number * second_number)
26}
27
28fn print(result: Result<i32, ParseIntError>) {
29    match result {
30        Ok(n)  => println!("n is {}", n),
31        Err(e) => println!("Error: {}", e),
32    }
33}
34
35fn main() {
36    print(multiply("10", "2"));
37    print(multiply("t", "2"));
38}
39```
40
41At this point, we've learned to explicitly handle errors using combinators
42and early returns. While we generally want to avoid panicking, explicitly
43handling all of our errors is cumbersome.
44
45In the next section, we'll introduce `?` for the cases where we simply
46need to `unwrap` without possibly inducing `panic`.
47