Các công dụng khác của ?

Trong ví dụ trước hãy lưu ý rằng phản ứng tức thời của chúng tôi đối với việc gọi parse là để map lỗi từ một lỗi thư viện vào môt lỗi được đóng gói:

#![allow(unused)]
fn main() {
.and_then(|s| s.parse::<i32>()
    .map_err(|e| e.into())
}

Vì đây là một thao tác đơn giản và phổ biến, nên sẽ rất thuận tiện nếu nó có thể được bỏ qua. Than ôi, bởi vì and_then không đủ linh hoạt, nên không thể. Tuy nhiên, thay vào đó chúng ta có thể sử dụng ?.

Trước đó ? đã được giải thích là unwrap hoặc return Err(err). Điều này chỉ đúng phần nào, thực tế nó có nghĩa là unwrap hoặc return Err(From::from(err). Do From::from là một tiện ích để chuyển đổi giữa các kiểu khác nhau, điều này có nghĩa là nếu bạn sử dụng ? lỗi có thể tự động chuyển đổi thành kiểu trả về .

Dưới đây, chúng tôi viết lại ví dụ trước bằng cách sử dụng ?. Kết quả là, khi From::from được thực thi nó làm biến mất lỗi map_err.

use std::error;
use std::fmt;

// Thay đổi bí danh thành `Box<dyn error::Error>`.
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;

#[derive(Debug)]
struct EmptyVec;

impl fmt::Display for EmptyVec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "invalid first item to double")
    }
}

impl error::Error for EmptyVec {}

// Cấu trúc giống như trước đây nhưng thay vì xâu chuỗi tất cả `Results`
// và `Option` lại với nhau, chúng ta sử dụng `?` để lấy giá trị bên trong ngay lập tức.

fn double_first(vec: Vec<&str>) -> Result<i32> {
    let first = vec.first().ok_or(EmptyVec)?;
    let parsed = first.parse::<i32>()?;
    Ok(2 * parsed)
}

fn print(result: Result<i32>) {
    match result {
        Ok(n)  => println!("The first doubled is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    print(double_first(numbers));
    print(double_first(empty));
    print(double_first(strings));
}

Điều này thực sự khá rõ ràng. So với panic ban đầu, nó rất giống với việc thay thế các lời gọi unwrap bằng ? ngoại trừ các kiểu trả về là Result. DO đó, chúng được phân giải ra ở cấp cao nhất.

Xem thêm

From::from?