دروس الوحدة (5/5)
"تأجيل": تنظيف مضمون
defer يؤجل تنفيذ المكالمة ** حتى وظيفة التضمين
يعود **. يتم تشغيله حتى إذا خرجت الوظيفة عن طريق الذعر. عدة defers
في نفس الوظيفة، يتم تنفيذها بترتيب LIFO (آخر دخول، أول صادر).
إنها الآلية الاصطلاحية لـ تنظيف الموارد: إغلاق الملفات، فتح كائنات المزامنة، وتحرير الاتصالات، واستعادة الحالة.
حالة الاستخدام النحوي والأساسي
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // chiamata SEMPRE all'uscita della funzione
// ... usa f liberamente ...
return nilنموذجي: f.Close()، mu.Unlock()، db.Close()، tx.Rollback()،
محمي_INLINE_9.
تم تقييم الحجج على الفور، وتم تأجيل التنفيذ
عندما تكتب defer foo(x)، يتم تقييم x في وقت
defer، ليس في وقت التنفيذ:
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"طلب LIFO
يتم تجميع المؤجلات وتنفيذها بدءًا من الأحدث:
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1وهذا يتوافق مع دلالات الموارد: آخر ما تم فتحه هو الأول لتكون مغلقة.
defer + recover: التعامل مع الذعر
defer هي الطريقة الوحيدة لاعتراض panic:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}المأزق: defer في حلقة
يؤدي وضع defer f.Close() في حلقة إلى تأخير ** حتى نهاية
الوظيفة**، وليس كل تكرار. في حلقة طويلة يمكنك فتح العديد من الملفات
وأغلقها فقط عند خروج الوظيفة: خطر تسرب واصف الملف.
// MALE: defer accumulati
for _, path := range paths {
f, _ := os.Open(path)
defer f.Close() // chiude TUTTI alla fine della funzione esterna
// ...
}
// MEGLIO: estrai in una funzione
for _, path := range paths {
elabora(path) // ogni chiamata ha il proprio scope di defer
}جربه
اطبع "inizio"، ثم قم بتأجيل طباعة "الغرامة" مع التأجيل، ثم اطبع "mezzo". يجب أن يكون الإخراج: inizio / mezzo / غرامة.
إظهار التلميح
يتم تشغيل التأجيل عندما يكون main() على وشك العودة.
الحل متاح بعد 3 من المحاولات
اكتب ثلاثة تأجيلات متتالية تطبع 1 و2 و3 بهذا الترتيب في الكود. سيكون الإخراج 3/2/1 (LIFO).
إظهار التلميح
ثلاثة تأجيلات بالتسلسل؛ تذكر أنها تنفذ بترتيب عكسي.
الحل متاح بعد 3 من المحاولات
ماذا يطبع هذا؟ (ملاحظة: يتم تقييم وسيطات التأجيل على الفور)
x := 10
defer fmt.Println(x)
x = 99خلاصة
defer call()يؤجل التنفيذ حتى تعود الوظيفة.- التأجيلات المتعددة = أمر LIFO.
- تم تقييم الوسيطات على الفور، وتم تأجيل التنفيذ.
- يستخدم للتنظيف الحتمي: الملفات، وكائنات المزامنة، والاتصالات.
defer+recover()يعترضpanic(نادرًا، عند الحدود).- لا
deferأبدًا داخل حلقة طويلة: فهي تتراكم حتى تعود الوظيفة الخارجية.