اذهب إلى أفضل الممارسات - معالجة الأخطاء

هذه هي المقالة الأولى في سلسلة من الدروس التي تعلمتها على مدار العامين الماضيين عملت مع Go في الإنتاج. إننا ندير عددًا كبيرًا من خدمات Go في الإنتاج في Saltside Technologies (psst ، أنا أوظف لشغل وظائف متعددة في Bangalore for Saltside) وأدير أيضًا عملي الخاص حيث Go هي جزء لا يتجزأ.

سوف نغطي مجموعة واسعة من الموضوعات ، كبيرها وصغيرها.

الموضوع الأول الذي أردت تغطيته في هذه السلسلة هو معالجة الأخطاء. غالبًا ما يتسبب في حدوث تشويش وإزعاج لمطوري Go الجدد.

بعض الخلفية - واجهة الخطأ

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

اكتب واجهة خطأ {
    خطأ () سلسلة
}

لذلك يمكن استخدام أي شيء ينفذ أسلوب سلسلة Error () كخطأ.

التحقق من الأخطاء

باستخدام هياكل الخطأ ونوع التحقق

عندما بدأت في الكتابة ، غالبًا ما قمت بإجراء مقارنات سلسلة لرسائل الخطأ لمعرفة نوع الخطأ (نعم ، محرج للتفكير فيه ولكن في بعض الأحيان تحتاج إلى التراجع إلى الأمام).

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

إليك مثال لتنفيذ الخطأ.

النوع ErrZeroDivision struct {
    سلسلة الرسالة
}
func NewErrZeroDivision (سلسلة الرسائل) * ErrZeroDivision {
    return & ErrZeroDivision {
        الرسالة:
    }
}
سلسلة func (e * ErrZeroDivision) Error () {
    إرجاع الرسالة الإلكترونية
}

الآن يمكن استخدام هذا الخطأ مثل هذا.

func main () {
    النتيجة ، يخطئ: = القسمة (1.0 ، 0.0)
    إذا أخطأت! = لا شيء
        التبديل يخطئ. (النوع) {
        الحالة * ErrZeroDivision:
            fmt.Println (err.Error ())
        الإفتراضي:
            fmt.Println ("ما حدث h * فقط؟")
        }
    }
    fmt.Println (نتيجة)
}
func divide (a، b float64) (float64، error) {
    إذا ب == 0.0 {
        إرجاع 0.0 ، NewErrZeroDivision ("لا يمكن القسمة على صفر")
    }
    إرجاع أ / ب ، لا شيء
}

إليك رابط Go Play للحصول على المثال الكامل. لاحظ نمط التبديل (النوع) الخاص بالخطأ ، والذي يجعل من الممكن التحقق من أنواع الأخطاء المختلفة بدلاً من شيء آخر (مثل مقارنة السلسلة أو شيء مشابه).

باستخدام حزمة الأخطاء والمقارنة المباشرة

بدلاً من ذلك ، يمكن التعامل مع النهج أعلاه باستخدام حزمة الأخطاء. يُنصح بهذا النهج للتحقق من الأخطاء داخل الحزمة حيث تحتاج إلى تمثيل خطأ سريع.

var errNotFound = errors.New ("العنصر غير موجود")
func main () {
    err: = getItem (123) // هذا من شأنه أن يلقي errNotFound
    إذا أخطأت! = لا شيء
        التبديل يخطئ {
        حالة errNotFound:
            log.Println ("العنصر المطلوب غير موجود")
        الإفتراضي:
            log.Println ("حدث خطأ غير معروف")
        }
    }
}

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

معالجة خطأ فورية

أحيانًا أجد رمزًا مثل ما يلي (ولكن عادةً ما يكون لدي المزيد من الزغب حولك ..):

خطأ func example1 () {
    يخطئ: = call1 ()
    عودة يخطئ
}

النقطة هنا هي أنه لا يتم معالجة الخطأ على الفور. هذا أسلوب هش نظرًا لأن شخصًا ما يمكنه إدراج رمز بين err: = call1 () والإرجاع err ، والذي قد يكسر النية ، لأن ذلك قد يظل الخطأ الأول. نهجين بديلين:

// طي الإرجاع والخطأ.
خطأ func example2 () {
    إرجاع call1 ()
}
// قم بمعالجة الأخطاء الصريحة مباشرة بعد المكالمة.
خطأ func example3 ()
    يخطئ: = call1 ()
    إذا أخطأت! = لا شيء
        عودة يخطئ
    }
    عودة لا شيء
}

كل من النهج المذكورة أعلاه على ما يرام معي. أنها تحقق نفس الشيء ، وهو ؛ إذا احتاج شخص ما إلى إضافة شيء ما بعد call1 () فيجب عليه الاهتمام بمعالجة الأخطاء.

هذا كل شيء لهذا اليوم

ترقبوا المقالة التالية حول Go Best Practices. الذهاب قوي :).

func main () {
    err: = readArticle ("Go Best Practices - Error handling")
    إذا أخطأت! = لا شيء
        بينغ ( "@ sebdah")
    }
}