Lekcje modułu (5/5)
`defer`: gwarantowane czyszczenie
defer opóźnia wykonanie wywołania ** do czasu załączenia funkcji
zwraca**. Działa nawet jeśli funkcja zakończy się w wyniku paniki. Wiele defer
w tej samej funkcji wykonaj w kolejności LIFO (ostatnie weszło, pierwsze wyszło).
Jest to idiomatyczny mechanizm czyszczenia zasobów: zamykania plików, odblokowywanie muteksów, zwalnianie połączeń, przywracanie stanu.
Składnia i kanoniczny przypadek użycia
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // chiamata SEMPRE all'uscita della funzione
// ... usa f liberamente ...
return nilTypowe: f.Close(), mu.Unlock(), db.Close(), tx.Rollback(),
KODEF4.
Argumenty oceniane natychmiast, wykonanie odroczone
Kiedy piszesz defer foo(x), x jest oceniany w momencie
defer, nie w momencie wykonania:
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"Kolejność LIFO
Odracza układanie i wykonywanie, zaczynając od najnowszego:
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1Jest to zgodne z semantyką zasobów: ostatni otwarty jest pierwszym być zamknięte.
defer + recover: obsługa paniki
defer to jedyny sposób na przechwycenie panic:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}Pułapka: defer w pętli
Umieszczenie defer f.Close() w pętli kumuluje się, odracza aż do końca
funkcji, a nie każdej iteracji. W długiej pętli otwierasz wiele plików
i zamykaj je dopiero po zakończeniu funkcji: ryzyko wycieku deskryptora pliku.
// 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
}Spróbuj
Wydrukuj „inizio”, następnie odrocz wydruk „fine” za pomocą odroczenia, a następnie wydrukuj „mezzo”. Wynik musi brzmieć: inizio / mezzo / fine.
Pokaż wskazówkę
Odroczenie jest uruchamiane, gdy funkcja main() ma wkrótce powrócić.
Rozwiązanie dostępne po 3 próbach
Zapisz trzy kolejne odroczenia, które wypiszą w kodzie cyfry 1, 2 i 3 w tej kolejności. Wyjście będzie wynosić 3/2/1 (LIFO).
Pokaż wskazówkę
Trzy odroczenia po kolei; pamiętaj, że wykonują się w odwrotnej kolejności.
Rozwiązanie dostępne po 3 próbach
Co to drukuje? (uwaga: argumenty odroczenia są oceniane natychmiast)
x := 10
defer fmt.Println(x)
x = 99Podsumowanie
defer call()opóźnia wykonanie do czasu powrotu funkcji.- Wiele odroczeń = porządek LIFO.
- Argumenty rozpatrywane natychmiast, wykonanie odroczone.
- Używany do deterministycznego czyszczenia: plików, muteksów, połączeń.
defer+recover()przechwytujepanic(rzadko, na granicach).- Nigdy nie używaj
deferw długiej pętli: gromadzi się do momentu powrotu funkcji zewnętrznej.