معالجة الأخطاء في Go: try/catch وما بعدها — دليل شامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

معالجة الأخطاء في Go: فلسفة بدون try/catch

في عالم Go (Golang) لا توجد آلية try/catch المألوفة للعديد من المطورين. هذا ليس مصادفة، بل قرار معماري واعٍ. اعتبر مبتكرو اللغة أن المعالجة الصريحة للأخطاء تجعل الكود أكثر موثوقية وقابلية للقراءة. بدلاً من إخفاء الاستثناءات في مكدس الاستدعاءات، تقدم Go للمبرمج فكرة التحقق دائمًا من نتيجة كل عملية يحتمل أن تكون خطرة. في هذا المقال سنشرح جميع الأساليب الأساسية لمعالجة الأخطاء في Go: من error الأساسي إلى panic و recover القويين، وسنوضح أيضًا كيفية كتابة كود لا يتعطل في أكثر اللحظات غير المناسبة.



1. الآلية الأساسية: واجهة error

أساس معالجة الأخطاء في Go هو الواجهة المضمنة error. تحتوي على طريقة واحدة فقط:

type error interface {    Error() string}

أي دالة قد تفشل في إتمام مهمتها يجب أن تعيد error كقيمة أخيرة. من المعتاد إعادة nil إذا لم يكن هناك خطأ، وقيمة غير صفرية إذا حدث عطل.

مثال على المعالجة الأساسية:

package main

import ( "errors" "fmt")

func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("القسمة على صفر غير ممكنة") } return a / b, nil}

func main() { result, err := divide(10, 0) if err != nil { fmt.Println("خطأ:", err) return } fmt.Println("النتيجة:", result)}

هذا هو ما يعادل try/catch في Go — التحقق الصريح if err != nil. هذا الأسلوب يجبر المطور على التفكير في الأخطاء في كل خطوة.



2. أنواع الأخطاء المخصصة والتغليف (wrapping)

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

إنشاء خطأ مخصص:

type DivisionError struct {    Dividend float64    Divisor  float64    Message  string}

func (e *DivisionError) Error() string { return fmt.Sprintf("خطأ في القسمة: %s (المقسوم: %f, المقسوم عليه: %f)", e.Message, e.Dividend, e.Divisor)}

func safeDivide(a, b float64) (float64, error) { if b == 0 { return 0, &DivisionError{Dividend: a, Divisor: b, Message: "المقسوم عليه يساوي صفر"} } return a / b, nil}

تغليف الأخطاء (wrapping):
ابتداءً من Go 1.13، أصبح من الممكن تغليف خطأ داخل آخر، مع إضافة سياق:

import "fmt"

func readConfig(path string) error { file, err := openFile(path) if err != nil { return fmt.Errorf("تعذرت قراءة ملف الإعدادات %s: %w", path, err) } defer file.Close() // ... قراءة الملف return nil}

التوجيه %w ينشئ سلسلة من الأخطاء. لاحقًا يمكنك التحقق مما إذا كان الخطأ من نوع معين باستخدام errors.Is() و errors.As().



3. Panic و Recover: حالات الطوارئ

أحيانًا يحدث شيء لا يجب أن يحدث من الأساس — الخروج عن حدود المصفوفة، إلغاء مرجعية مؤشر فارغ. في مثل هذه الحالات تستخدم Go panic. هذا ليس بديلاً عن try/catch، بل آلية للأخطاء الحرجة غير القابلة للاسترداد.

مثال على panic:

func main() {    arr := []int{1, 2, 3}    fmt.Println(arr[10]) // panic: runtime error: index out of range}

ومع ذلك، إذا كنت تريد "التقاط" الذعر واستعادة التنفيذ، يتم استخدام recover مع defer. هذا هو أقرب ما يعادل catch.

مثال على recover:

func safeCall(f func()) {    defer func() {        if r := recover(); r != nil {            fmt.Pr                

المدونات

توصيات الكتب