דילוג לתוכן המרכזי
מודול 3 · שיעור 5 מתוך 515/50 בקורס~12 min
שיעורי מודול (5/5)

`דחיית`: ניקוי מובטח

defer דוחה את ביצוע השיחה עד לפונקציה המקיפה מחזיר. זה פועל גם אם הפונקציה יוצאת בפאניקה. מספר defers באותה פונקציה לבצע בסדר LIFO (Last-In, First-Out).

זה המנגנון האידיומטי לניקוי משאבים: סגירת קבצים, ביטול נעילת מוטקסים, שחרור חיבורים, שחזור מצב.

תחביר ומקרה שימוש קנוני

Go
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(), recover().

הטיעונים הוערכו מיד, הביצוע נדחה

כאשר אתה כותב defer foo(x), x מוערך בזמן ה defer, לא בזמן הביצוע:

Go
x := 10
defer fmt.Println(x)   // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"

הוראת LIFO

דוחה ערימה וביצוע החל מהאחרון:

Go
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1

זה עולה בקנה אחד עם סמנטיקה של משאבים: האחרון שנפתח הוא הראשון להיות סגור.

defer + recover: טיפול בפאניקה

defer היא הדרך היחידה ליירט panic:

Go
func safe() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("recuperato:", r)
        }
    }()
    panic("boom")
}

מלכודת: defer בלולאה

הכנסת defer f.Close() ללולאה צוברת דחיות עד סוף הפונקציה, לא של כל איטרציה. בלולאה ארוכה פותחים קבצים רבים ולסגור אותם רק כשהפונקציה יוצאת: סיכון לדליפה של מתאר קבצים.

Go
// 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
}

נסה את זה

פעילות גופנית#go.m3.l5.e1
ניסיונות: 0טוען...

הדפס 'inizio', לאחר מכן דחה את ההדפסה של 'בסדר' עם דחה, ואז הדפס 'מצו'. הפלט חייב להיות: inizio / mezzo / fine.

טוען עורך...
הצג רמז

ה-defer פועל כאשר main() עומד לחזור.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#go.m3.l5.e2
ניסיונות: 0טוען...

כתוב שלוש דחיות רצופות שמדפיסות את 1, 2 ו-3 בסדר הזה בקוד. הפלט יהיה 3/2/1 (LIFO).

טוען עורך...
הצג רמז

שלושה דחיות ברצף; זכור שהם מבצעים בסדר הפוך.

הפתרון זמין לאחר 3 ניסיונות

Quiz#go.m3.l5.e3
מוכן

מה זה מדפיס? (הערה: טיעונים לדחייה מוערכים באופן מיידי)

Go
x := 10
defer fmt.Println(x)
x = 99
אפשרויות תשובה

לְסַכֵּם

  • defer call() דוחה את הביצוע עד שהפונקציה תחזור.
  • דחיות מרובות = סדר LIFO.
  • הטיעונים הוערכו מיד, הביצוע נדחה.
  • משמש לניקוי דטרמיניסטי: קבצים, מוטקסים, חיבורים.
  • defer + recover() מיירט panic (נדיר, בגבולות).
  • לעולם אל defer בתוך לולאה ארוכה: היא מצטברת עד שהפונקציה החיצונית חוזרת.