W Go standardowe podejście to obsługa błędów przez zwracanie wartości error. Pozwala to wyraźnie kontrolować, co robić w przypadku wystąpienia błędu w każdym punkcie. Panic to mechanizm do obsługi nieprzewidzianych katastrofalnych sytuacji: przerywa wykonanie do najbliższego defer, gdzie można użyć recover do "uratowania". Ale recover działa tylko wewnątrz defer.
Najlepsze praktyki:
func safeDivide(a, b int) (int, error) { if b == 0 { return 0, errors.New("dzielenie przez zero") } return a/b, nil } func mustDivide(a, b int) int { if b == 0 { panic("dzielenie przez zero!") } return a/b }
Czy można "złapać" każdą panikę z pomocą recover w dowolnym miejscu programu?
Odpowiedź: Nie, recover zadziała tylko wewnątrz defer i tylko w tej samej gorutynie, w której wystąpiła panika. W innych przypadkach panika zakończy wykonanie tej (lub wszystkich) gorutin — to często staje się zaskoczeniem.
Historia
W REST API używano panic do obsługi zwykłych błędów w logice biznesowej. Doprowadziło to do nieoczywistych awarii aplikacji i nieprawidłowych logów, ponieważ recover nie zawsze działał prawidłowo.
Historia
W usłudze przetwarzania płatności zrealizowano defer + recover w funkcji głównej, aby "łapać" wszystkie paniki, ale zapomniano o gorutinach — w podrzędnych gorutynach bez defer/recover aplikacja padała z "przerażającymi" błędami, pozostawiając część transakcji w niespójnym stanie.
Historia
W parserze złożonych struktur zapomniano zwrócić błąd, zastępując go panic — to skomplikowało utrzymanie i testowanie, konieczne było przepisanie obsługi błędów, aby mieć szczegółowe logowanie i poprawne UX.