defer
تأجيل التنفيذ حتى العودة defer
defer يجدول استدعاء دالة لينفَّذ مباشرة قبل عودة الدالة المحيطة — الأداة القياسية لضمان التنظيف (إغلاق ملف، فكّ قفل...) مهما كان مسار الخروج.
defer statement يأخذ استدعاء دالة وبدل تنفيذه فورًا يؤجّله لينفَّذ بالضبط قبل لحظة عودة الدالة الحالية، سواء وصلت لـ return عادي أو خرجت بسبب panic. هذا يجعله الأداة الأساسية لأي عملية تنظيف يجب أن تحدث مهما كان مسار الخروج: إغلاق ملف بعد فتحه، فكّ قفل mutex بعد قفله، إغلاق اتصال شبكة.
لو وُجد أكثر من defer بنفس الدالة، تُنفَّذ بترتيب عكسي (LIFO) — آخر defer كُتب هو أول ما يُنفَّذ. وسائط الدالة المؤجَّلة تُقيَّم فورًا وقت كتابة defer نفسه، لا وقت التنفيذ الفعلي.
الصياغة
defer functionCall(args)
📄 مثال
func process() {
fmt.Println("بداية")
defer fmt.Println("أولاً يُكتب — آخر ما يُطبع")
defer fmt.Println("ثانيًا يُكتب — يُطبع قبل الأول")
fmt.Println("نهاية الدالة")
}
// الناتج:
// بداية
// نهاية الدالة
// ثانيًا يُكتب — يُطبع قبل الأول
// أولاً يُكتب — آخر ما يُطبعأهم النقاط
| العنصر | الوظيفة |
|---|---|
| defer f() | ينفّذ f() قبل عودة الدالة الحالية مباشرة |
| ترتيب LIFO | آخر defer مكتوب هو أول ما يُنفَّذ |
| تقييم الوسائط | قيم الوسائط تُحسب فورًا وقت كتابة defer، لا وقت التنفيذ |
💡 نصائح عملية
- ضع defer file.Close() مباشرة بعد فتح الملف بنجاح — لا تنتظر نهاية الدالة كي لا تنساها بمسار خروج آخر
- دمجه مع recover() هو الطريقة الوحيدة لالتقاط panic في Go
⚠️ أخطاء شائعة
- استخدام defer داخل حلقة طويلة (مثلًا لإغلاق ملفات كثيرة) يراكم كل الاستدعاءات حتى نهاية الدالة كلها بدل كل تكرار — قد يستنزف الموارد
- الظن أن defer ينفّذ فورًا — بالعكس، ينفَّذ فقط عند عودة الدالة المحيطة كاملة
خصائص ذات صلة
🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار GO الكامل بالعربي.