Używanie `recover`
Część sekcji Logika i przepływ sterowania ścieżki GO w Coddy. Lekcja 43 z 68.
Chociaż panic natychmiast zatrzymuje program, Go umożliwia odzyskanie kontroli za pomocą funkcji recover. Funkcja recover pozwala przechwycić panikę i obsłużyć ją w kontrolowany sposób, zapobiegając awarii całego programu.
Jednak recover ma bardzo konkretne wymaganie: można go używać tylko wewnątrz odroczonej funkcji. Gdy wystąpi panika, Go wykonuje wszystkie odroczone funkcje przed zakończeniem programu, dając recover szansę na przechwycenie paniki:
func riskyFunction() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
panic("something went wrong!")
}Funkcja recover zwraca wartość przekazaną do panic lub nil, jeśli nie wystąpiła panika. Dzięki temu możesz sprawdzić, czy wystąpiła panika, i podjąć odpowiednie działania, takie jak zapisanie błędu w dzienniku lub wykonanie operacji porządkowych.
Podobnie jak panic, recover należy stosować oszczędnie w Go. Najczęściej używa się go w sytuacjach takich jak działanie serwerów WWW, gdy chcesz zapobiec temu, by panika podczas obsługi pojedynczego żądania spowodowała awarię całego serwera, dzięki czemu może on nadal obsługiwać inne żądania.
Wyzwanie
ŁatwyZbuduj procedurę obsługi żądań serwera WWW, która używa recover, aby łagodnie obsługiwać paniki i zapobiegać awarii całego serwera. To wyzwanie pokazuje, jak używać recover wewnątrz odroczonej funkcji, aby przechwytywać paniki i utrzymywać stabilność serwera.
Otrzymasz dwa wejścia:
- Ciąg zawierający szczegóły żądania w formacie
"endpoint,method,action"(np."/api/users,GET,process") - Ciąg zawierający konfigurację serwera w formacie
"server_name,max_requests"(np."WebServer,100")
Twoim zadaniem jest:
- Przeanalizować pierwsze wejście, dzieląc je po przecinkach, aby uzyskać endpoint, method i action
- Przeanalizować drugie wejście, dzieląc je po przecinkach, aby uzyskać nazwę serwera i maksymalną liczbę żądań
- Przekonwertować ciąg z maksymalną liczbą żądań na liczbę całkowitą
- Utworzyć funkcję o nazwie
handleRequest, która przyjmuje endpoint, method, action i nazwę serwera jako parametry - Wewnątrz
handleRequestdodać odroczoną funkcję, która używarecover, aby przechwycić wszelkie paniki:- Jeśli panika zostanie przechwycona (
recoverzwraca wartość różną od nil), wyświetlić:"Server [server_name] recovered from panic: [panic_value]" - Po obsłużeniu paniki wyświetlić:
"Request handling completed safely"
- Jeśli panika zostanie przechwycona (
- Po odroczonej funkcji zasymulować przetwarzanie żądania w zależności od działania:
- Jeśli action to
"process": wyświetlić"Processing [method] request to [endpoint]" - Jeśli action to
"panic_nil": wyświetlić"Attempting dangerous operation", a następnie wywołaćpanic("nil pointer access") - Jeśli action to
"panic_overflow": wyświetlić"Attempting resource allocation", a następnie wywołaćpanic("memory overflow") - Jeśli action to
"panic_timeout": wyświetlić"Attempting database connection", a następnie wywołaćpanic("connection timeout") - Dla każdej innej wartości action: wyświetlić
"Unknown action: [action]", a następnie wywołaćpanic("invalid action")
- Jeśli action to
- W funkcji main wyświetlić komunikat o uruchomieniu serwera:
"Starting [server_name] with max [max_requests] requests" - Wywołać funkcję
handleRequestz przeanalizowanymi parametrami - Po wywołaniu funkcji wyświetlić status serwera:
"Server [server_name] is still running" - Na koniec wyświetlić podsumowanie:
"Server Summary:""Name: [server_name]""Max Requests: [max_requests]""Last Request: [method] [endpoint]""Action Performed: [action]""Status: Operational"
Użyj pakietu strings, aby dzielić ciągi wejściowe po przecinkach, oraz pakietu strconv, aby przekonwertować ciąg z maksymalną liczbą żądań na liczbę całkowitą. To wyzwanie pokazuje, jak recover pozwala serwerom łagodnie obsługiwać nieoczekiwane paniki, zapobiegając temu, by awarie pojedynczych żądań unieruchamiały cały system.
Spróbuj swoich sił
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// Odczytaj dane wejściowe
var requestDetails string
var serverConfig string
fmt.Scanln(&requestDetails)
fmt.Scanln(&serverConfig)
// Przeanalizuj szczegóły żądania
requestParts := strings.Split(requestDetails, ",")
endpoint := requestParts[0]
method := requestParts[1]
action := requestParts[2]
// Przeanalizuj konfigurację serwera
configParts := strings.Split(serverConfig, ",")
serverName := configParts[0]
maxRequests, _ := strconv.Atoi(configParts[1])
// TODO: Napisz swój kod poniżej
// Utwórz funkcję handleRequest z mechanizmem recover
// Wyświetl komunikat o uruchomieniu serwera
// Wywołaj funkcję handleRequest
// Wyświetl stan serwera i podsumowanie
}Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Logika i przepływ sterowania
1Zaawansowane sterowanie przepływem
Instrukcja switch z `fallthrough`Przerywanie zagnieżdżonych pętliKontynuowanie określonej pętliInstrukcja `goto`Podsumowanie — zaawansowane sterowanie pętlami4Projekt: Prosta lista zadań
Konfiguracja projektuDodawanie zadania7Obsługa błędów — dogłębnie
Własne typy błędówOpakowywanie błędów za pomocą `%w`Rozpakowywanie za pomocą `errors.Is`Rozpakowywanie za pomocą `errors.As`Zrozumienie `panic`Używanie `recover`Podsumowanie — bezpieczne dzielenie2Struktury i metody
Definiowanie metod dla strukturOdbiorniki przez wartośćOdbiorniki przez wskaźnikWybór odbiornikówMetody a funkcjePodsumowanie — działanie struktur5Mapy w szczegółach
Mapy strukturWskaźniki jako wartości mapSprawdzanie, czy mapy są nilPorównywanie mapPodsumowanie — licznik częstości słów3Interfejsy (podstawy)
Czym jest interfejs?Definiowanie interfejsuImplementowanie interfejsuUżywanie typów interfejsowychPusty interfejsAsercje typuPrzełącznik typówPodsumowanie – kształty i zachowaniaPoćwicz samodzielnie: Kompilator Go online