۸

مدیریت خطا

روش امن و استاندارد Rust برای مدیریت خطاها با `Result` و `Option`.

خطاهای قابل بازیابی در مقابل غیرقابل بازیابی

Rust خطاها رو به دو دسته تقسیم می‌کنه:

  • خطاهای غیرقابل بازیابی (Unrecoverable): اینا خطاهای خیلی جدی هستن که برنامه نمی‌تونه ازشون به سلامت عبور کنه. Rust در این مواقع با ماکروی `panic!` برنامه رو متوقف می‌کنه.
  • خطاهای قابل بازیابی (Recoverable): اینا خطاهایی هستن که انتظار داریم اتفاق بیفتن، مثل پیدا نشدن یه فایل. برای این موارد، Rust از `enum` ای به اسم `Result` استفاده می‌کنه.

`Result`: موفقیت یا شکست

`Result` یه `enum` هست با دو حالت: `Ok(T)` که مقدار موفقیت‌آمیز رو نگه می‌داره، و `Err(E)` که اطلاعات خطا رو نگه می‌داره. ما با `match` می‌تونیم هر دو حالت رو مدیریت کنیم.

use std::fs::File;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => panic!("Problem opening the file: {:?}", error),
    };
}

اپراتور `?`: راه میان‌بر برای خطاها

نوشتن `match` های تودرتو می‌تونه خسته‌کننده باشه. اپراتور `?` یه راه خیلی تمیز برای انتشار (Propagate) خطاهاست. اگه نتیجه یه عملیات `Ok` باشه، مقدار داخلش رو برمی‌گردونه. اگه `Err` باشه، کل تابع رو متوقف می‌کنه و اون خطا رو به کسی که تابع رو صدا زده برمی‌گردونه.

use std::fs::File;
use std::io::{self, Read};

// این تابع یا محتوای فایل رو برمی‌گردونه یا خطا رو
fn read_username_from_file() -> Result {
    let mut f = File::open("hello.txt")?; // اگه خطا بده، از تابع خارج می‌شه
    let mut s = String::new();
    f.read_to_string(&mut s)?; // اگه اینجا هم خطا بده، خارج می‌شه
    Ok(s) // اگه همه چی خوب بود، نتیجه موفق رو برمی‌گردونه
}