التعامل مع الأخطاء (Error Handling)
في البرامج الحقيقية، الأخطاء أمر حتمي. قد يُدخل المستخدم قيمة غير صحيحة، أو قد يفشل الاتصال بالإنترنت، أو قد نحاول القسمة على صفر. بدلاً من ترك البرنامج ينهار، يمكننا التعامل مع الأخطاء بأناقة باستخدام نظام begin/rescue/end في روبي.
ما هو الخطأ (Exception)؟
الخطأ هو حدث غير متوقع يقطع التنفيذ الطبيعي للبرنامج:
بدون معالجة الأخطاء:
- البرنامج يتوقف فوراً
- المستخدم يرى رسالة خطأ تقنية
- البيانات قد تضيع
البنية الأساسية: begin/rescue/end
مثال عملي: القسمة الآمنة
بدون معالجة: البرنامج ينهار عند القسمة على صفر مع المعالجة: يعرض رسالة ودية ويستمر
التقاط نوع محدد من الأخطاء
يمكننا تحديد نوع الخطأ الذي نريد التقاطه:
أنواع الأخطاء الشائعة
| نوع الخطأ | متى يحدث | مثال |
|---|---|---|
ZeroDivisionError | القسمة على صفر | 10 / 0 |
NoMethodError | استدعاء دالة غير موجودة | nil.upcase |
NameError | متغير غير معرف | puts unknown |
TypeError | نوع بيانات خاطئ | "hello" + 5 |
ArgumentError | عدد أو نوع المعاملات خاطئ | [1,2].first(1, 2) |
RuntimeError | خطأ عام أثناء التشغيل | raise "خطأ!" |
التقاط أنواع متعددة
التقاط عدة أنواع معاً
الوصول لمعلومات الخطأ
استخدم => e للحصول على كائن الخطأ:
مثال مفصل
إلقاء الأخطاء باستخدام raise
يمكننا إلقاء (إنشاء) أخطاء خاصة بنا:
raise بسيط
raise مع نوع محدد
إنشاء أنواع أخطاء مخصصة
ensure: شيفرة تُنفذ دائماً
ensure يُنفذ سواء حدث خطأ أو لا - مفيد للتنظيف:
مثال: إدارة الموارد
else: عند نجاح الشيفرة
else يُنفذ فقط إذا لم يحدث خطأ:
البنية الكاملة
retry: إعادة المحاولة
retry يعيد تنفيذ الشيفرة من بداية begin:
تحذير: احذر من الحلقات اللانهائية! دائماً حدد عدد المحاولات.
مثال عملي شامل: حاسبة آمنة
جدول ملخص
| الكلمة | الوظيفة | متى يُنفذ |
|---|---|---|
begin | بداية الشيفرة المحمي | دائماً |
rescue | معالجة الخطأ | عند حدوث خطأ |
else | شيفرة النجاح | عند عدم حدوث خطأ |
ensure | شيفرة التنظيف | دائماً (بعد rescue أو else) |
raise | إلقاء خطأ | عند استدعائه |
retry | إعادة المحاولة | عند استدعائه في rescue |
أفضل الممارسات
1. التقط أخطاء محددة
2. لا تبتلع الأخطاء
3. استخدم ensure للتنظيف
أخطاء شائعة
1. نسيان حد retry
2. rescue واسع جداً
3. raise بدون معلومات
ملخص
| المفهوم | الوصف |
|---|---|
begin/rescue/end | البنية الأساسية لمعالجة الأخطاء |
rescue ErrorType | التقاط نوع محدد من الأخطاء |
rescue => e | الوصول لكائن الخطأ |
raise | إلقاء خطأ جديد |
ensure | شيفرة تُنفذ دائماً للتنظيف |
else | شيفرة تُنفذ عند النجاح فقط |
retry | إعادة المحاولة (بحذر!) |
تمرين: القسمة الآمنة
حان وقت التطبيق! في محرر الشيفرة على اليسار:
المطلوب:
-
اكتب دالة
safe_divide(a, b)تقوم بـ:- محاولة قسمة
aعلىb - إذا كان
bصفراً، تطبع رسالة خطأ وترجعnil - إذا نجحت العملية، ترجع الناتج
- محاولة قسمة
-
اختبر الدالة بالقيم:
safe_divide(10, 2)- يجب أن يطبع الناتج 5safe_divide(10, 0)- يجب أن يطبع رسالة خطأ
الناتج المتوقع:
تلميحات:
- استخدم
begin/rescue/endداخل الدالة - استخدم
rescue ZeroDivisionErrorلالتقاط خطأ القسمة على صفر - اطبع
"الناتج: #{result}"عند النجاح - اطبع
"خطأ: لا يمكن القسمة على صفر!"عند الفشل
تذكّر: معالجة الأخطاء تجعل برامجك أكثر متانة وودية للمستخدم. استخدم
begin/rescue/endللتعامل مع الحالات غير المتوقعة، وraiseلإلقاء أخطاء ذات معنى، وensureلضمان تنظيف الموارد. في الدرس القادم سنبدأ التحديات البرمجية لتطبيق كل ما تعلمناه!