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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Luckily, Option's map, and_then, and many other combinators are also implemented for Result. Result contains a complete listing.

use std::num::ParseIntError;

// As with `Option`, we can use combinators such as `map()`.

// This function is otherwise identical to the one above and reads:

// Modify n if the value is valid, otherwise pass on the error.

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

first_number_str.parse::<i32>().and_then(|first_number| {

second_number_str.parse::<i32>().map(|second_number| first_number * second_number)

})

}

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

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

How about when we want to reuse a specific Result type many times? Recall that Rust allows us to create aliases. Conveniently, we can define one for the specific Result in question.

At a module level, creating aliases can be particularly helpful. Errors found in a specific module often have the same Err type, so a single alias can succinctly define all associated Results. This is so useful that the std library even supplies one: io::Result!

Here's a quick example to show off the syntax:

use std::num::ParseIntError;

// Define a generic alias for a `Result` with the error type `ParseIntError`.

type AliasedResult<T> = Result<T, ParseIntError>;

// Use the above alias to refer to our specific `Result` type.

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

first_number_str.parse::<i32>().and_then(|first_number| {

second_number_str.parse::<i32>().map(|second_number| first_number * second_number)

})

}

// Here, the alias again allows us to save some space.

fn print(result: AliasedResult<i32>) {

match result {

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

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

}

}

fn main() {

print(multiply("10", "2"));

print(multiply("t", "2"));

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

io::Result

In the previous example, we explicitly handled the errors using combinators. Another way to deal with this case analysis is to use a combination of match statements and early returns.

That is, we can simply stop executing the function and return the error if one occurs. For some, this form of code can be easier to both read and write. Consider this version of the previous example, rewritten using early returns:

use std::num::ParseIntError;

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

let first_number = match first_number_str.parse::<i32>() {

Ok(first_number) => first_number,

Err(e) => return Err(e),

};

let second_number = match second_number_str.parse::<i32>() {

Ok(second_number) => second_number,

Err(e) => return Err(e),

};

Ok(first_number * second_number)

}

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

match result {

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

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

}

}

fn main() {

print(multiply("10", "2"));

print(multiply("t", "2"));

}

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

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX