Lompati ke konten utama
Modul 3 · Pelajaran 5 dari 515/50 dalam kursus~12 min
Pelajaran modul (5/5)

`defer`: jaminan pembersihan

defer menunda pelaksanaan panggilan hingga fungsi penutup kembali. It runs even if the function exits via panic. Multiple defers dalam fungsi yang sama dijalankan dalam urutan LIFO (Masuk Terakhir, Keluar Pertama).

Ini adalah mekanisme idiomatis untuk pembersihan sumber daya: menutup file, membuka kunci mutex, melepaskan koneksi, memulihkan status.

Sintaks dan kasus penggunaan kanonik

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

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

Argumen segera dievaluasi, eksekusi ditunda

Saat Anda menulis defer foo(x), x dievaluasi pada saat defer, not at execution time:

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

pesanan LIFO

Defers menumpuk dan mengeksekusi dimulai dengan yang terbaru:

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

Hal ini konsisten dengan semantik sumber daya: yang terakhir dibuka adalah yang pertama untuk ditutup.

defer + recover : menangani kepanikan

defer adalah satu-satunya cara untuk mencegat panic:

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

Kesalahan: defer dalam satu lingkaran

Menempatkan defer f.Close() dalam satu lingkaran akan terakumulasi penundaan hingga akhir the function, not of each iteration. In a long loop you open many files dan hanya menutupnya ketika fungsinya keluar: risiko kebocoran deskriptor file.

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
}

Cobalah

Latihan#go.m3.l5.e1
Upaya: 0Memuat…

Cetak 'inizio', lalu tunda cetak 'fine' dengan defer, lalu cetak 'mezzo'. Outputnya harus: inizio / mezzo / fine.

Memuat editor…
Tunjukkan petunjuk

Penundaan berjalan ketika main() akan kembali.

Solusi tersedia setelah 3 upaya

Latihan#go.m3.l5.e2
Upaya: 0Memuat…

Tulis tiga penundaan berturut-turut yang mencetak 1, 2 dan 3 sesuai urutan kode. Outputnya akan menjadi 3/2/1 (LIFO).

Memuat editor…
Tunjukkan petunjuk

Tiga penundaan secara berurutan; ingat mereka mengeksekusi dalam urutan terbalik.

Solusi tersedia setelah 3 upaya

Quiz#go.m3.l5.e3
Siap

Apa yang dicetak ini? (catatan: argumen penangguhan segera dievaluasi)

Go
x := 10
defer fmt.Println(x)
x = 99
Pilihan jawaban

Rekap

  • defer call() menunda eksekusi hingga fungsinya kembali.
  • Multiple defers = LIFO order.
  • Argumen segera dievaluasi, eksekusi ditunda.
  • Digunakan untuk pembersihan deterministik: file, mutex, koneksi.
  • defer + recover() mencegat panic (jarang, di perbatasan).
  • Jangan pernah defer di dalam loop panjang: ini terakumulasi hingga fungsi luar kembali.