این تبدیل‌ها (Conversions) را امتحان کنید

گسترش مؤثر ? کمی پیچیده‌تر از آنچه قبلاً ذکر شد است:

expression?

به طو مشابه کار می‌کند

match expression {
    Ok(value) => value,
    Err(err)  => return Err(From::from(err)),
}

فراخوانی From::from در اینجا به این معنی است که ما سعی می کنیم نوع خطا را به نوع بازگشتی توسط تابع تبدیل کنیم. این باعث می‌شود که خطاها به خطاهای سطح بالاتر کپسوله شوند.

مثال

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::fs::File;
use std::io::{self, Read};

#[derive(Debug)]
enum ReadUsernameError {
    IoError(io::Error),
    EmptyUsername(String),
}

impl Error for ReadUsernameError {}

impl Display for ReadUsernameError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Self::IoError(e) => write!(f, "IO error: {e}"),
            Self::EmptyUsername(path) => write!(f, "در این  {path} نام کاربری یافت نشد"),
        }
    }
}

impl From<io::Error> for ReadUsernameError {
    fn from(err: io::Error) -> Self {
        Self::IoError(err)
    }
}

fn read_username(path: &str) -> Result<String, ReadUsernameError> {
    let mut username = String::with_capacity(100);
    File::open(path)?.read_to_string(&mut username)?;
    if username.is_empty() {
        return Err(ReadUsernameError::EmptyUsername(String::from(path)));
    }
    Ok(username)
}

fn main() {
    //std::fs::write("config.dat", "").unwrap();
    let username = read_username("config.dat");
    println!("نام‌کاربری یا خطا: {username:?}");
}
This slide should take about 5 minutes.

عملگر ? باید مقداری سازگار با نوع بازگشتی تابع برگرداند. برای Result، به این معنی است که انواع خطا باید سازگار باشند. تابعی کهResult<T, ErrorOuter> را برمی‌گرداند، تنها می‌تواند از ? در مقداری از تایپ‌های Result<U, ErrorInner> استفاده کند اگر ErrorOuter و ErrorInner یک نوع باشند یا اگر ErrorOuter از` را پیاده‌سازی کند.

یک جایگزین رایج برای پیاده سازی Fromجهت Result::map_err است، به خصوص زمانی که تبدیل‌ها فقط در یک مکان انجام می‌شود.

هیچ الزامی برای سازگاری Option وجود ندارد. تابعی که Option<T> را برمی گرداند می تواند از عملگر ? در Option<U> برای انواع دلخواه T و U استفاده کند.

یک تابعی که Result را برمی‌گرداند دیگر نمی‌تواند از ? در Option استفاده کند و بالعکس. با این‌حال، Option::ok_or یک Option را به Result تبدیل می‌کند در حالی که Result::ok «نتیجه» را به Option تبدیل می‌کند.