Выбрать главу

Result is a richer version of the Option type that describes possible error instead of possible absence.

That is, Result<T, E> could have one of two outcomes:

   • Ok(T): An element T was found

   • Err(E): An error was found with element E

By convention, the expected outcome is Ok while the unexpected outcome is Err.

Like Option, Result has many methods associated with it. unwrap(), for example, either yields the element T or panics. For case handling, there are many combinators between Result and Option that overlap.

In working with Rust, you will likely encounter methods that return the Result type, such as the parse() method. It might not always be possible to parse a string into the other type, so parse() returns a Result indicating possible failure.

Let's see what happens when we successfully and unsuccessfully parse() a string:

fn multiply(first_number_str: &str, second_number_str: &str) -> i32 {

// Let's try using `unwrap()` to get the number out. Will it bite us?

let first_number = first_number_str.parse::<i32>().unwrap();

let second_number = second_number_str.parse::<i32>().unwrap();

first_number * second_number

}

fn main() {

let twenty = multiply("10", "2");

println!("double is {}", twenty);

let tt = multiply("t", "2");

println!("double is {}", tt);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

In the unsuccessful case, parse() leaves us with an error for unwrap() to panic on. Additionally, the panic exits our program and provides an unpleasant error message.

To improve the quality of our error message, we should be more specific about the return type and consider explicitly handling the error.

The Result type can also be the return type of the main function if specified explicitly. Typically the main function will be of the form:

fn main() {

println!("Hello World!");

}

However main is also able to have a return type of Result. If an error occurs within the main function it will return an error code and print a debug representation of the error (using the Debug trait). The following example shows such a scenario and touches on aspects covered in the following section.

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(())

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Panicking in the previous example's multiply does not make for robust code. Generally, we want to return the error to the caller so it can decide what is the right way to respond to errors.

We first need to know what kind of error type we are dealing with. To determine the Err type, we look to parse(), which is implemented with the FromStr trait for i32. As a result, the Err type is specified as ParseIntError.

In the example below, the straightforward match statement leads to code that is overall more cumbersome.

use std::num::ParseIntError;

// With the return type rewritten, we use pattern matching without `unwrap()`.

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {

match first_number_str.parse::<i32>() {

Ok(first_number) => {

match second_number_str.parse::<i32>() {

Ok(second_number) => {

Ok(first_number * second_number)

},

Err(e) => Err(e),

}

},

Err(e) => Err(e),

}

}

fn print(result: Result<i32, ParseIntError>) {

match result {

Ok(n) => println!("n is {}", n),

Err(e) => println!("Error: {}", e),

}

}

fn main() {

// This still presents a reasonable answer.

let twenty = multiply("10", "2");

print(twenty);

// The following now provides a much more helpful error message.

let tt = multiply("t", "2");

print(tt);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה