الانتقال إلى المحتوى الرئيسي
الوحدة 7 · الدرس 2 من 214/14 في الدورة~15 min
دروس الوحدة (2/2)

معالجة الأخطاء و؟ المشغل

تشجعك فلسفة Rust على التعرف على احتمالية حدوث أخطاء بشكل صريح وبناء التعليمات البرمجية الخاصة بك للتعامل معها قبل تجميع البرنامج.

تنقسم الأخطاء في Rust إلى فئتين رئيسيتين: الأخطاء غير القابلة للاسترداد (التي تتسبب في الإنهاء الفوري عبر الماكرو panic!) و الأخطاء القابلة للاسترداد (التي تتم إدارتها باستخدام النوع Result<T, E>).


النتيجة<T, E> مطابقة النوع والنمط

تُرجع معظم الأخطاء القابلة للاسترداد النوع Result<T, E>، وهو عبارة عن تعداد تم تعريفه على النحو التالي:

Rust
enum Result<T, E> {
    Ok(T),
    Err(E),
}

يمكننا استخدام مطابقة الأنماط لفحص النتيجة:

Rust
use std::fs::File;

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

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

انتشار الخطأ باستخدام عامل التشغيل ?

عند تنفيذ دالة، بدلًا من معالجة الخطأ بداخلها مباشرةً، غالبًا ما نرغب في إعادة الخطأ إلى المتصل حتى يتمكن من تحديد ما يجب فعله. تسمى هذه العملية انتشار الخطأ.

يوفر Rust عامل التشغيل ? كاختصار نحوي لنشر الأخطاء. إذا كانت قيمة Result هي Ok، فسيتم إرجاع القيمة الداخلية لـ Ok بواسطة التعبير؛ إذا كان Err، فسيتم إرجاع الخطأ Err من الوظيفة الحالية بأكملها كما لو أننا استخدمنا return Err(...).

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

fn read_username_from_file() -> Result<String, io::Error> {
    let mut username_file = File::open("username.txt")?;
    let mut username = String::new();
    username_file.read_to_string(&mut username)?;
    Ok(username)
}

[!هام] لا يمكن استخدام عامل التشغيل ? إلا في الوظائف التي تُرجع نوعًا متوافقًا مع القيمة المطبقة عليها (عادةً Result، أو Option، أو الأنواع التي تنفذ FromResidual).


الأخطاء المخصصة

يمكننا تحديد أنواع الأخطاء المخصصة الخاصة بنا من خلال تطبيق السمة std::fmt::Display (واختياريًا std::error::Error) لتوفير تمثيل للخطأ يمكن قراءته بواسطة الإنسان:

Rust
use std::fmt;

#[derive(Debug)]
struct MyError {
    details: String,
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error: {}", self.details)
    }
}

impl std::error::Error for MyError {}

جربه بنفسك

التمرين 1: قراءة ملف بالملحق ? مشغل

تمرين#rust.m7.l2.e1
المحاولات: 0جارٍ التحميل…

أكمل وظيفة read_username_from_file بحيث تستخدم ؟ عامل التشغيل لنشر الأخطاء الناتجة عن فتح الملف وقراءة محتواه في سلسلة اسم المستخدم.

جارٍ تحميل المحرر…
إظهار التلميح

أضف `؟`الحرف بعد`File::open(...)`وبعد`username_file.read_to_string(...)` لنشر الأخطاء.

الحل متاح بعد 3 من المحاولات

التمرين 2: تحليل الرقم ومضاعفته

تمرين#rust.m7.l2.e2
المحاولات: 0جارٍ التحميل…

اكتب دالة باسم parse_and_double تقبل مرجع سلسلة &str وترجع نتيجة <i32, std::num::ParseIntError>. يجب أن تقوم الدالة بتحليل السلسلة باستخدام val.parse::<i32>() مع ؟ لنشر أخطاء التحليل، وعند النجاح، قم بإرجاع القيمة المضاعفة المغلفة بـ Ok.

جارٍ تحميل المحرر…
إظهار التلميح

استخدم `val.parse::<i32>()?` لتحليل السلسلة ونشر الخطأ، ثم قم بإرجاع`Ok(num \* 2)`.

الحل متاح بعد 3 من المحاولات

التمرين 3: تحديد خطأ مخصص

تمرين#rust.m7.l2.e3
المحاولات: 0جارٍ التحميل…

قم بتعريف بنية فارغة تسمى CustomError. قم بتنفيذ سمة العرض std::fmt::Display الخاصة بها عن طريق كتابة "Si e verificato un errore Personalizzato" كرسالة خطأ في طريقة fmt.

جارٍ تحميل المحرر…
إظهار التلميح

قم بتعريف `struct CustomError;`` وتنفيذ العرض عن طريق الكتابة`write!(f, "Si e verificato un errore Personalizzato")`داخل الأسلوب`fmt`.

الحل متاح بعد 3 من المحاولات