Salt la conținutul principal
Modulul 3 · Lecția 5 din 515/50 în curs~12 min
Lecții din modul (5/5)

`defer`: curățare garantată

defer amână executarea unui apel până la funcția de anexare se întoarce. Funcționează chiar dacă funcția iese prin panică. Mai multe defers în aceeași funcție, executați în ordinea LIFO (Last-In, First-Out).

Este mecanismul idiomatic pentru curățarea resurselor: închiderea fișierelor, deblocarea mutexurilor, eliberarea conexiunilor, restabilirea stării.

Sintaxă și caz de utilizare canonic

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

Tipic: f.Close(), mu.Unlock(), db.Close(), tx.Rollback(), recover().

Argumente evaluate imediat, execuția amânată

Când scrieți defer foo(x), x este evaluat la momentul defer, nu la momentul execuției:

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

Comanda LIFO

Amânările se adună și se execută începând cu cea mai recentă:

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

Acest lucru este în concordanță cu semantica resurselor: ultimul deschis este primul să fie închis.

defer + recover: gestionarea panicii

defer este singura modalitate de a intercepta un panic:

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

Capcană: defer într-o buclă

Punerea defer f.Close() într-o buclă se acumulează amână până la sfârșitul funcția, nu a fiecărei iterații. Într-o buclă lungă deschideți multe fișiere și închideți-le numai când funcția iese: risc de scurgere de descriptor de fișier.

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
}

Încearcă

Exercițiu#go.m3.l5.e1
Încercări: 0Se încarcă…

Tipăriți „inizio”, apoi amânați tipărirea „fine” cu defer, apoi tipăriți „mezzo”. Ieșirea trebuie să fie: inizio / mezzo / fine.

Se încarcă editorul...
Afișează indiciu

Amânarea rulează când main() este pe cale să revină.

Soluție disponibilă după 3 încercări

Exercițiu#go.m3.l5.e2
Încercări: 0Se încarcă…

Scrieți trei amânări consecutive care imprimă 1, 2 și 3 în această ordine în cod. Ieșirea va fi 3 / 2 / 1 (LIFO).

Se încarcă editorul...
Afișează indiciu

Trei amânări în succesiune; amintiți-vă că se execută în ordine inversă.

Soluție disponibilă după 3 încercări

Quiz#go.m3.l5.e3
Gata

Ce imprimă asta? (notă: argumentele deferă sunt evaluate imediat)

Go
x := 10
defer fmt.Println(x)
x = 99
Opțiuni de răspuns

Recapitulare

  • defer call() amână execuția până când funcția revine.
  • Amânări multiple = ordin LIFO.
  • Argumente evaluate imediat, execuția amânată.
  • Folosit pentru curățarea deterministă: fișiere, mutexuri, conexiuni.
  • defer + recover() interceptează un panic (rar, la granițe).
  • Niciodată defer într-o buclă lungă: se acumulează până când funcția exterioară revine.