فك التغليف باستخدام `errors.As`
جزء من قسم Logic & Flow في رحلة GO على Coddy — الدرس 41 من 68.
بينما تساعدك errors.Is على تحديد قيم أخطاء محددة في سلسلة (chain)، ستحتاج أحياناً إلى الوصول إلى الحقول والبيانات الفعلية لنوع خطأ مخصص. توفر الدالة errors.As هذه الإمكانية من خلال العثور على أول خطأ في سلسلة يطابق نوعاً معيناً واستخراجه للفحص.
تأخذ الدالة errors.As معاملين: الخطأ المراد فحصه ومؤشرًا لمتغير من نوع الخطأ المستهدف. إذا وجدت نوع خطأ مطابقًا في السلسلة، فإنها تقوم بتعيين المتغير الخاص بك إلى ذلك الخطأ وتعيد القيمة true:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}هذا قوي بشكل خاص عند العمل مع أنواع الأخطاء المخصصة التي تحتوي على سياق إضافي. على عكس errors.Is الذي يتحقق فقط من التساوي، يقوم errors.As باستخراج مثيل الخطأ الفعلي، مما يسمح لك بالوصول إلى حقوله وطرقه. وهذا يجعل معالجة الأخطاء أكثر تطوراً وغنى بالمعلومات في التطبيقات المعقدة.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
التحدي
سهلقم ببناء نظام لمعالجة أخطاء واجهة برمجة التطبيقات (API) يستخدم errors.As لاستخراج وفحص أنواع الأخطاء المخصصة من سلاسل الأخطاء المغلفة (wrapped error chains). يوضح هذا التحدي كيفية استخدام errors.As للوصول إلى الحقول والبيانات الخاصة بأنواع الأخطاء المخصصة، حتى عندما يتم تغليفها بسياق إضافي.
ستتلقى مدخلين:
- سلسلة نصية تحتوي على تفاصيل طلب API بتنسيق
"endpoint,method,error_code,error_field"(على سبيل المثال،"/users,POST,400,email") - سلسلة نصية تحتوي على سياق النظام بتنسيق
"service_name,request_id"(على سبيل المثال،"UserAPI,req_12345")
مهمتك هي:
- إنشاء نوع خطأ مخصص يسمى
APIErrorكبنية (struct) تحتوي على ثلاثة حقول:Code(int) - رمز حالة HTTPField(string) - الحقل الذي تسبب في الخطأMessage(string) - وصف للخطأ
- تنفيذ تابع
Error() stringلـAPIErrorوالذي يعيد:"API error [code]: [message] (field: [field])" - تحليل المدخل الأول عن طريق التقسيم عند الفواصل للحصول على endpoint و method و error code و error field
- تحليل المدخل الثاني عن طريق التقسيم عند الفواصل للحصول على service name و request ID
- تحويل سلسلة رمز الخطأ النصية إلى عدد صحيح (integer)
- إنشاء مثيل من
APIErrorبناءً على رمز الخطأ:- إذا كان الرمز 400: الرسالة
"invalid request data" - إذا كان الرمز 401: الرسالة
"authentication required" - إذا كان الرمز 404: الرسالة
"resource not found" - إذا كان الرمز 500: الرسالة
"internal server error" - لأي رمز آخر: الرسالة
"unknown error"
- إذا كان الرمز 400: الرسالة
- إنشاء خطأ مغلف على مستوى الـ endpoint باستخدام
fmt.Errorfمع%w:"[method] [endpoint] failed: %w" - إنشاء خطأ مغلف على مستوى الخدمة (service-level):
"[service_name] request [request_id] failed: %w" - استخدام
errors.AsلاستخراجAPIErrorمن سلسلة الأخطاء المغلفة وعرض نتيجة الاستخراج:- إذا نجح الاستخراج:
"API error extracted successfully" - إذا فشل الاستخراج:
"Failed to extract API error"
- إذا نجح الاستخراج:
- إذا نجح الاستخراج، قم بعرض تفاصيل الخطأ المستخرج:
"Extracted Error Details:""Code: [code]""Field: [field]""Message: [message]""Full error: [full_error_message_from_Error_method]"
- عرض سلسلة الأخطاء الكاملة:
"Error Chain:""Original: [original_api_error_message]""Endpoint level: [endpoint_level_error_message]""Service level: [service_level_error_message]"
- عرض تحليل نهائي:
"Error Analysis:""Service: [service_name]""Request ID: [request_id]""Endpoint: [method] [endpoint]""HTTP Status: [code]""Problem Field: [field]""Error Category: [error_category]"حيث يكون error_category هو "Client Error" للأكواد 400-499، أو "Server Error" للأكواد 500-599، أو "Unknown" للأكواد الأخرى
استخدم حزمة strings لتقسيم سلاسل المدخلات عند الفواصل، وحزمة strconv لتحويل سلسلة رمز الخطأ إلى عدد صحيح، وحزمة errors من أجل errors.As، وحزمة fmt لتغليف الأخطاء. يوضح هذا التحدي كيف تتيح لك errors.As الوصول إلى الحقول والأساليب المحددة لأنواع الأخطاء المخصصة داخل سلاسل الأخطاء المغلفة، مما يتيح معالجة وتحليل الأخطاء بشكل متطور.
ورقة مرجعية
تقوم الدالة errors.As باستخراج أنواع أخطاء محددة من سلاسل الأخطاء، مما يسمح بالوصول إلى حقول وطرق الأخطاء المخصصة.
تأخذ errors.As معاملين: الخطأ المراد فحصه ومؤشر (pointer) لمتغير من نوع الخطأ المستهدف:
var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}على عكس errors.Is التي تتحقق فقط من التساوي، تقوم errors.As باستخراج مثيل الخطأ الفعلي، مما يتيح الوصول إلى حقوله وطرقه لمعالجة أخطاء أكثر تطوراً.
جرّب بنفسك
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// قراءة المدخلات
var apiDetails string
var systemContext string
fmt.Scanln(&apiDetails)
fmt.Scanln(&systemContext)
// تحليل المدخلات
apiParts := strings.Split(apiDetails, ",")
endpoint := apiParts[0]
method := apiParts[1]
errorCodeStr := apiParts[2]
errorField := apiParts[3]
contextParts := strings.Split(systemContext, ",")
serviceName := contextParts[0]
requestID := contextParts[1]
// تحويل رمز الخطأ إلى عدد صحيح
errorCode, _ := strconv.Atoi(errorCodeStr)
// TODO: اكتب الكود الخاص بك أدناه
// 1. قم بإنشاء هيكل APIError مع حقول Code و Field و Message
// 2. قم بتنفيذ طريقة Error() لهيكل APIError
// 3. قم بإنشاء مثيل APIError بناءً على رمز الخطأ
// 4. قم بإنشاء أخطاء مغلفة (على مستوى نقطة النهاية وعلى مستوى الخدمة)
// 5. استخدم errors.As لاستخراج APIError من سلسلة الأخطاء المغلفة
// 6. عرض نتيجة الاستخراج وتفاصيل الخطأ
// 7. عرض سلسلة الأخطاء والتحليل النهائي
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Logic & Flow
1تدفق التحكم المتقدم
جملة Switch مع `fallthrough`الخروج من الحلقات المتداخلةالاستمرار في حلقة محددةجملة `goto`ملخص - التحكم المتقدم في الحلقات7معالجة الأخطاء بعمق
أنواع الأخطاء المخصصةتغليف الأخطاء باستخدام `%w`فك التغليف باستخدام `errors.Is`فك التغليف باستخدام `errors.As`فهم `panic`استخدام `recover`ملخص - القسمة الآمنة2الـ Structs والميثودز (Methods)
تعريف الـ Methods على الـ Structsالـ Value Receiversالـ Pointer Receiversاختيار الـ Receiversالـ Methods مقابل الـ Functionsملخص - سلوك الـ Struct5تعمق في الـ Maps
Maps من نوع Structsالـ Pointers كقيم في الـ Mapsالتحقق من الـ Nil Mapsمقارنة الـ Mapsمراجعة - عداد تكرار الكلمات3الواجهات (الأساسيات)
ما هي الواجهة؟تعريف الواجهةتطبيق الواجهةاستخدام أنواع الواجهاتالواجهة الفارغةتأكيدات النوع (Type Assertions)تبديل النوع (Type Switch)ملخص - الأشكال والسلوكيات