Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تغليف الأخطاء (fmt.Errorf)

جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 54 من 107.

عندما تمر الأخطاء عبر طبقات متعددة من تطبيقك، يصبح من الضروري معرفة مكان نشوء الخطأ. تتيح لك الدالة fmt.Errorf في Go، باستخدام معامل %w، تغليف الأخطاء مع الحفاظ على الخطأ الأصلي وإضافة سياق.

يُنشئ تغليف الأخطاء سلسلةً من الأخطاء. ويمكن لكل طبقة إضافة معلومات حول ما كانت تحاول فعله عند حدوث الخطأ:

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    // معالجة البيانات...
    return nil
}

الفعل %w مميّز. فهو يغلّف الخطأ الأصلي داخل الخطأ الجديد. وهذا يختلف عن %v، الذي يحوّل الخطأ فقط إلى سلسلة نصية ويفقد هوية الخطأ الأصلي.

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

عندما تفشل LoadSettings، تعرض رسالة الخطأ السلسلة الكاملة: "loading settings: reading config file: open settings.json: no such file or directory". تضيف كل طبقة سياقًا، مما يجعل تصحيح الأخطاء أسهل بكثير.

لا يزال الخطأ المُغلَّف يحتوي على الخطأ الأصلي بداخله. في الدرس التالي، ستتعلّم كيفية فكّ تغليف هذه الأخطاء والتحقق مما بداخلها باستخدام errors.Is() وerrors.As().

challenge icon

التحدي

سهل

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

ستنظّم التعليمات البرمجية في ملفين:

  • orders.go: أنشئ منطق معالجة الطلبات مع طبقات متعددة تغلّف الأخطاء أثناء انتشارها إلى الأعلى.

    نفّذ ثلاث دوال تشكّل سلسلة معالجة:

    • ValidateItem(itemID string) error - تُرجع خطأً برسالة "item not found" إذا كانت قيمة itemID هي "INVALID"، وإلا فتُرجع nil
    • ProcessOrder(orderID, itemID string) error - تستدعي ValidateItem. إذا أعادت خطأً، فغلّفه بالسياق: "processing order [orderID]: %w". وإلا فأرجع nil
    • SubmitOrder(customerName, orderID, itemID string) error - تستدعي ProcessOrder. إذا أعادت خطأً، فغلّفه بالسياق: "submitting order for [customerName]: %w". وإلا فأرجع nil

    يجب أن تستخدم كل طبقة fmt.Errorf مع العامل %w لتغليف الخطأ القادم من الطبقة الأدنى، وبناء سلسلة من السياقات.

  • main.go: اقرأ تفاصيل الطلب من الإدخال، واستدعِ SubmitOrder، واعرض النتيجة. إذا حدث خطأ، فاطبع سلسلة الأخطاء الكاملة. وإذا نجحت العملية، فاطبع رسالة تأكيد.

ستُوفَّر المدخلات التالية:

  • السطر 1: اسم العميل
  • السطر 2: معرّف الطلب
  • السطر 3: معرّف العنصر

اطبع النتيجة:

  • إذا حدث خطأ: Error: [full error chain]
  • إذا نجحت العملية: Order [orderID] submitted successfully for [customerName]

على سبيل المثال، عند إعطاء Alice وORD-123 وINVALID، يجب أن يكون الناتج:

Error: submitting order for Alice: processing order ORD-123: item not found

لاحظ كيف تعرض رسالة الخطأ السلسلة الكاملة. يمكنك تتبّع المشكلة من محاولة الإرسال على المستوى الأعلى، مرورًا بمعالجة الطلب، وصولًا إلى فشل التحقق الفعلي. أضافت كل طبقة سياقها الخاص باستخدام %w.

وعند إعطاء Bob وORD-456 وITEM-001، يجب أن يكون الناتج:

Order ORD-456 submitted successfully for Bob

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// اقرأ اسم العميل
	scanner.Scan()
	customerName := scanner.Text()
	
	// اقرأ معرف الطلب
	scanner.Scan()
	orderID := scanner.Text()
	
	// اقرأ معرف العنصر
	scanner.Scan()
	itemID := scanner.Text()
	
	// TODO: استدعِ SubmitOrder بالقيم المدخلة
	// TODO: إذا حدث خطأ، اطبع: Error: [full error chain]
	// TODO: If successful, print: Order [orderID] submitted successfully for [customerName]
	
	_ = customerName
	_ = orderID
	_ = itemID
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Go عبر الإنترنت