map for Result

Khi xảy ra lỗi trong hàm multiply của ví dụ trước, sử dụng panic không tạo ra mã nguồn mạnh mẽ. Thông thường, chúng ta muốn trả lại lỗi cho người gọi hàm để người gọi hàm quyết định cách phản hồi với lỗi đó. Đầu tiên, chúng ta cần phải biết loại lỗi mà chúng ta đang gặp phải. Để xác định kiểu Err, chúng ta tìm kiểu lỗi trong parse(), Được thực hiện bằng cách triển khai trait FromStr cho i32. Kết quả là, kiểu Err được xác định là kiểu ParseIntError.

Trong ví dụ dưới đây, câu lệnh match trực tiếp dẫn đến mã nguồn tổng thể phức tạp hơn.

use std::num::ParseIntError;

// Với kiểu trả về được viết lại, chúng ta sử dụng phân tích mẫu mà không có `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() {
   // Điều này vẫn cho phép trả về một câu trả lời hợp lý.
    let twenty = multiply("10", "2");
    print(twenty);

    // Bây giờ đoạn mã sau đây cung cấp một thông báo lỗi hữu ích hơn nhiều.
    let tt = multiply("t", "2");
    print(tt);
}

May mắn thay, các phương thức Option's map, and_then và nhiều phương thức khác cũng được cài đặt cho Result. Result chứa một danh sách đầy đủ.

use std::num::ParseIntError;

// Giống với `Option`, chúng ta có thể sử dụng các phương thức kết hợp như `map()`.
// Hàm này tương tự như hàm trên và có chức năng: 
// Nhân nếu cả hai giá trị có thể được phân tích từ chuỗi, nếu không truyền lỗi cho phía gọi hàm xử lý.
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() {
    // Điều này vẫn cho phép trả về một câu trả lời hợp lý.
    let twenty = multiply("10", "2");
    print(twenty);

    // Bây giờ đoạn mã sau đây cung cấp một thông báo lỗi hữu ích hơn nhiều.
    let tt = multiply("t", "2");
    print(tt);
}