Rust by Example

16.3.1 map for Result

Panicking in the previous example gave us an unhelpful error message. To avoid that, we need to be more specific about the return type. There, the regular element is of type i32.

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. Luckily, the map method of Option is one of many combinators also implemented for Result. enum.Result contains a complete listing.

use std::num::ParseIntError;

// With the return type rewritten, we use pattern matching without `unwrap()`.
fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
    match number_str.parse::<i32>() {
        Ok(n)  => Ok(2 * n),
        Err(e) => Err(e),
    }
}

// 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 double_number_map(number_str: &str) -> Result<i32, ParseIntError> {
    number_str.parse::<i32>().map(|n| 2 * n)
}

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 = double_number("10");
    print(twenty);

    // The following now provides a much more helpful error message.
    let tt = double_number_map("t");
    print(tt);
}