Słowo kluczowe defer w Go odkłada wykonanie wskazanych funkcji do momentu wyjścia z otaczającej funkcji — funkcje są gromadzone na stosie i wykonywane w odwrotnej kolejności (LIFO). Często wykorzystuje się to do zwalniania zasobów (pliki, mutexy, połączenia).
Cechą szczególną jest to, że wszystkie argumenty funkcji przekazanych do defer są obliczane natychmiast w momencie deklaracji, a nie podczas wykonania.
func test() { for i := 0; i < 3; i++ { defer fmt.Println(i) // Wydrukuje: 2, 1, 0 } }
Co wyniknie z poniższego kodu?
func main() { for i := 0; i < 3; i++ { defer fmt.Println(i) } }
Odpowiedź:
To wydrukuje:
2
1
0
Ponieważ w każdym cyklu argument i jest obliczany natychmiast (w momencie defer), a wszystkie wartości są przechowywane na stosie defer.
Historia
W serwisie plikowym zapomniano uwzględnić, że defer jest wywoływane tylko przy normalnym wyjściu z funkcji. Pojawiły się wycieki, gdy program awaryjnie kończył się przed punktem wywołania defer.
Historia
W potoku danych nastąpiło zapomnienie — w pętli używano defer do zamykania połączeń, ale faktycznie zamknęły się one dopiero po zakończeniu całej funkcji, a nie po każdej iteracji. Doprowadziło to do wyczerpania zasobów.
Historia
W loggerze używano defer z funkcją anonimową, oczekując, że argument zostanie obliczony w momencie wywołania. Z tego powodu log na końcu zawierał nieaktualne informacje, ponieważ wartości były przechwytywane wcześniej.