panic, recover i defer
Kiedy wywoływać panic i jak bezpiecznie odzyskiwać działanie
panic, recover i defer to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.
Czym jest panic?
panic przerywa normalne wykonywanie bieżącej goroutine, rozwija stos wywołań, uruchamiając odroczone funkcje, i powoduje awarię programu, jeśli nie zostanie obsłużone:
package main
import "fmt"
func mustPositive(n int) int {
if n <= 0 {
panic(fmt.Sprintf("mustPositive: got %d", n))
}
return n
}
func main() {
fmt.Println(mustPositive(5)) // 5
// fmt.Println(mustPositive(-1)) // panics!
}Kiedy używać panic
Używaj panic tylko w przypadku:
- Naprawdę niemożliwych do odzyskania błędów programisty (naruszenia niezmienników)
- Niemożliwych warunków wskazujących na błąd
- Niepowodzeń podczas uruchamiania (brak konfiguracji, nieudane połączenia podczas inicjalizacji)
Nigdy nie używaj panic w przypadku oczekiwanych niepowodzeń — użyj zamiast tego error.
Podstawy defer
defer odracza wywołanie funkcji do momentu zakończenia funkcji otaczającej, niezależnie od sposobu jej zakończenia (normalnego, przez błąd lub panikę):
package main
import "fmt"
func main() {
defer fmt.Println("third")
defer fmt.Println("second") // LIFO order
defer fmt.Println("first")
fmt.Println("running...")
// Output:
// running...
// first
// second
// third
}defer do sprzątania zasobów
Najczęściej defer służy do zapewnienia zwolnienia zasobów:
package main
import ("fmt"; "os")
func readFile(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("open: %w", err)
}
defer f.Close() // always runs, even if we return early
buf := make([]byte, 1024)
n, _ := f.Read(buf)
return string(buf[:n]), nil
}recover — przechwytywanie panik
recover zatrzymuje panikę i zwraca jej wartość. Musi zostać wywołane bezpośrednio wewnątrz funkcji defer:
package main
import "fmt"
func safeDiv(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered from panic: %v", r)
}
}()
return a / b, nil // panics if b==0
}
func main() {
r, err := safeDiv(10, 0)
fmt.Println(r, err)
// 0 recovered from panic: runtime error: integer divide by zero
}recover musi być wywołane w odroczonej funkcji
recover działa tylko wtedy, gdy zostanie wywołane bezpośrednio wewnątrz odroczonej funkcji. Wywołanie go w innym miejscu zwraca nil:
package main
import "fmt"
func wrong() {
// recover() here does nothing — not in defer
}
func correct() {
defer func() {
if r := recover(); r != nil {
fmt.Println("caught:", r)
}
}()
panic("oops")
}
func main() { correct() }Panika w kodzie biblioteki
Kod biblioteki niemal nigdy nie powinien pozwalać, aby paniki wydostały się do kodu wywołującego. Na granicy zamieniaj paniki na błędy:
package main
import ("fmt"; "runtime/debug")
func safeCall(fn func()) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v\n%s", r, debug.Stack())
}
}()
fn()
return nil
}
func main() {
err := safeCall(func() { panic("boom") })
fmt.Println(err != nil) // true
}Kolejność LIFO defer i pułapka w pętli
Odroczone wywołania wykonują się w kolejności ostatni weszło, pierwsze wyszło (LIFO). Uważaj na odraczanie wywołań wewnątrz pętli — użyj domknięcia lub funkcji pomocniczej:
package main
import "fmt"
func processFiles(names []string) {
for _, name := range names {
name := name // capture loop variable
defer func() { fmt.Println("close:", name) }()
}
}
func main() {
processFiles([]string{"a.txt", "b.txt", "c.txt"})
// Output (LIFO): close: c.txt, close: b.txt, close: a.txt
}defer z nazwanymi wartościami zwracanymi
Odroczone funkcje mogą odczytywać i modyfikować nazwane wartości zwracane — jest to przydatne do dodawania informacji do błędów:
package main
import "fmt"
func doWork() (err error) {
defer func() {
if err != nil {
err = fmt.Errorf("doWork: %w", err)
}
}()
return fmt.Errorf("something failed")
}
func main() {
err := doWork()
fmt.Println(err) // doWork: something failed
}panic a error: przewodnik po wyborze
Wybór między panic a error:
- Używaj error: oczekiwane niepowodzenia (nie znaleziono pliku, przekroczenie limitu czasu sieci, nieprawidłowe dane wejściowe)
- Używaj panic: błędy programistyczne (dostęp do nil mapy, wyjście poza zakres), niemożliwe stany, błędy inicjalizacji
- Nigdy nie używaj panic na granicach API — kod wywołujący nie może go obsłużyć
- Przechwytuj paniki na najwyższym poziomie goroutine w serwerach, aby uniknąć awarii
Szybkie sprawdzenie
Gdzie należy wywołać recover(), aby przechwycić panikę?
Podsumowanie: panic, recover, defer
Podsumowanie:
panic: odwija stos, wykonuje odroczone wywołania i powoduje awarię, jeśli nie zostanie przechwyconydefer: wykonuje się przy wyjściu z funkcji (normalnym, po błędzie lub panice); kolejność LIFOrecover: zatrzymuje panikę i zwraca jej wartość; musi znajdować się wdefer- Paniki należy stosować w przypadku błędów programisty, a nie oczekiwanych niepowodzeń
- Na granicach API należy zamieniać paniki na błędy
Ucz się Go dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 51
- Lekcje
- 203
Często zadawane pytania
Czy lekcja „panic, recover i defer” jest bezpłatna?
Tak — pełny tekst „panic, recover i defer” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „panic, recover i defer”?
Kiedy wywoływać panic i jak bezpiecznie odzyskiwać działanie Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Go Academy?
Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „panic, recover i defer”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?
Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Interfejs error
- Tworzenie własnych błędów
- Opakowywanie i rozpakowywanie błędów
- panic, recover i defer