تغليف الأخطاء وإلغاء تغليفها
استخدام %w وerrors.Is وerrors.As
تغليف الأخطاء وإلغاء تغليفها درس مجاني في Go Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Go Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Go Academy 4 دروس في المجموع.
ما تغليف الأخطاء؟
يُضمّن تغليف الأخطاء خطأً أصليًا داخل خطأ جديد، مع الحفاظ على الخطأ الأصلي لفحصه برمجيًا وإضافة سياق. وقد أُدخل بشكل صحيح في Go 1.13:
package main
import ("fmt"; "errors")
var ErrDB = errors.New("database unreachable")
func queryUsers() error {
return fmt.Errorf("queryUsers: %w", ErrDB)
}
func loadProfile(id int) error {
return fmt.Errorf("loadProfile(%d): %w", id, queryUsers())
}
func main() {
err := loadProfile(42)
fmt.Println(err) // loadProfile(42): queryUsers: database unreachable
}عامل %w
استخدم %w (وليس %v) في fmt.Errorf لتغليف خطأ. ويمكن الوصول إلى الخطأ المغلّف عبر errors.Unwrap:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner error")
outer := fmt.Errorf("outer: %w", inner)
fmt.Println(outer) // outer: inner error
fmt.Println(errors.Unwrap(outer)) // inner error
fmt.Println(errors.Is(outer, inner)) // true
}errors.Unwrap
تُرجع errors.Unwrap الخطأ التالي في السلسلة (الخطأ المغلّف)، أو nil إذا لم يوجد:
package main
import ("fmt"; "errors")
type Layer struct{ msg string; err error }
func (l *Layer) Error() string { return l.msg }
func (l *Layer) Unwrap() error { return l.err }
func main() {
root := errors.New("root")
mid := &Layer{"mid", root}
top := &Layer{"top", mid}
fmt.Println(errors.Unwrap(top)) // mid
fmt.Println(errors.Unwrap(mid)) // root
fmt.Println(errors.Unwrap(root)) // <nil>
}errors.Is — اجتياز السلسلة
تفك errors.Is(err, target) تغليف سلسلة الأخطاء بشكل متكرر حتى تعثر على تطابق أو تصل إلى nil:
package main
import ("fmt"; "errors")
var ErrNotFound = errors.New("not found")
func findItem(id int) error {
return fmt.Errorf("findItem(%d): %w",
id, fmt.Errorf("repo: %w", ErrNotFound))
}
func main() {
err := findItem(7)
fmt.Println(errors.Is(err, ErrNotFound)) // true — deep in chain
fmt.Println(err) // full message chain
}errors.As — اجتياز السلسلة للبحث عن الأنواع
تجتاز errors.As(err, &target) السلسلة بحثًا عن خطأ يمكن إسناده إلى نوع target:
package main
import ("fmt"; "errors")
type StatusError struct{ Code int }
func (e *StatusError) Error() string { return fmt.Sprintf("status %d", e.Code) }
func doRequest() error {
return fmt.Errorf("request: %w", &StatusError{503})
}
func main() {
err := doRequest()
var se *StatusError
if errors.As(err, &se) {
fmt.Println("status code:", se.Code) // 503
}
}Unwrap مخصّص للسلاسل
طبّق Unwrap() error على نوع الخطأ المخصّص لدعم errors.Is وerrors.As:
package main
import ("fmt"; "errors")
type AppError struct {
Op string
Err error
}
func (e *AppError) Error() string { return fmt.Sprintf("%s: %v", e.Op, e.Err) }
func (e *AppError) Unwrap() error { return e.Err }
var ErrAuth = errors.New("unauthorized")
func main() {
err := &AppError{"login", ErrAuth}
fmt.Println(errors.Is(err, ErrAuth)) // true
}%v مقابل %w في fmt.Errorf
الفرق بين %v و%w:
package main
import ("fmt"; "errors")
func main() {
inner := errors.New("inner")
withV := fmt.Errorf("outer: %v", inner) // string only, no wrap
withW := fmt.Errorf("outer: %w", inner) // wraps inner
fmt.Println(errors.Is(withV, inner)) // false — not wrapped
fmt.Println(errors.Is(withW, inner)) // true — wrapped
}التغليف عمليًا: معالج HTTP
يجعل تغليف الأخطاء بشكل متسق تصحيح الأخطاء أسهل في أنظمة الإنتاج:
package main
import "fmt"
func dbQuery(sql string) error {
return fmt.Errorf("db.Query(%q): connection refused", sql)
}
func getUserByID(id int) (string, error) {
if err := dbQuery("SELECT * FROM users WHERE id=?"); err != nil {
return "", fmt.Errorf("getUserByID(%d): %w", id, err)
}
return "Alice", nil
}
func handler() error {
_, err := getUserByID(1)
if err != nil {
return fmt.Errorf("handler: %w", err)
}
return nil
}
func main() { fmt.Println(handler()) }errors.Join — تغليفات متعددة (Go 1.20 فأحدث)
تنشئ errors.Join خطأً يغلّف أخطاء متعددة. وتفحص errors.Is جميع هذه الأخطاء:
package main
import ("fmt"; "errors")
var ErrA = errors.New("err A")
var ErrB = errors.New("err B")
func main() {
joined := errors.Join(ErrA, ErrB)
fmt.Println(joined)
fmt.Println(errors.Is(joined, ErrA)) // true
fmt.Println(errors.Is(joined, ErrB)) // true
}أفضل ممارسات فك التغليف
إرشادات لتغليف الأخطاء:
- غلّف باستخدام
%wللحفاظ على الخطأ من أجل فحصه برمجيًا - أضف اسم العملية للسياق:
fmt.Errorf("funcName: %w", err) - لا تغلّف أخطاء Sentinel إذا لم يكن المتصلون سيستخدمون
errors.Is - تجنب تغليف السياق نفسه مرتين في كل مستوى
- طبّق
Unwrap()على الأنواع المخصّصة للمشاركة في السلاسل
تحقق سريع
ما الفرق بين استخدام %v و%w في fmt.Errorf؟
مراجعة: تغليف الأخطاء وفك تغليفها
الملخص:
- يغلّف
fmt.Errorf("ctx: %w", err)الخطأ مع سياق - تحصل
errors.Unwrapعلى الخطأ التالي في السلسلة - تجتاز
errors.Isالسلسلة بحثًا عن تطابق الهوية - تجتاز
errors.Asالسلسلة بحثًا عن تطابق النوع - تطبّق الأنواع المخصّصة
Unwrap() error - تغلّف
errors.Joinأخطاء متعددة (Go 1.20 فأحدث)
تعلم Go مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 51
- الدروس
- 203
الأسئلة الشائعة
هل درس «تغليف الأخطاء وإلغاء تغليفها» مجاني؟
نعم — نص درس «تغليف الأخطاء وإلغاء تغليفها» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Go Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Go Academy 4 دروس في المجموع.
ماذا ستتعلم في «تغليف الأخطاء وإلغاء تغليفها»؟
استخدام %w وerrors.Is وerrors.As تتمرن على Go Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Go Academy؟
لا تُشترط خبرة سابقة. Go Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «تغليف الأخطاء وإلغاء تغليفها»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Go Academy هذا؟
نعم. كل درس في Go Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- واجهة error
- إنشاء أخطاء مخصصة
- تغليف الأخطاء وإلغاء تغليفها
- panic وrecover وdefer