Opakowywanie błędów za pomocą `%w`
Część sekcji Logika i przepływ sterowania ścieżki GO w Coddy. Lekcja 39 z 68.
Gdy w aplikacji wystąpią błędy, często potrzebują dodatkowego kontekstu, gdy przemieszczają się w górę przez różne warstwy kodu. Go zapewnia skuteczny mechanizm, który to umożliwia: opakowywanie błędów za pomocą czasownika formatującego %w w funkcji fmt.Errorf.
Opakowywanie błędów pozwala dodać kontekstowe informacje do istniejącego błędu, zachowując pierwotny błąd. Tworzy to łańcuch błędów, który przechowuje pełną historię tego, co poszło nie tak:
originalErr := errors.New("file not found")
wrappedErr := fmt.Errorf("failed to load config: %w", originalErr)Specyfikator %w jest wyjątkowy — informuje fmt.Errorf, aby opakować błąd, zamiast po prostu przekształcać go w ciąg znaków. Dzięki temu oryginalny błąd zostaje zachowany i można go później sprawdzić za pomocą funkcji takich jak errors.Is i errors.As.
Ten wzorzec jest szczególnie przydatny w większych aplikacjach, w których błąd może przechodzić przez wiele funkcji, a każda z nich dodaje własny kontekst. Na przykład błąd połączenia z bazą danych może zostać opakowany komunikatem „nie udało się połączyć z bazą danych”, a następnie opakowany ponownie komunikatem „nie można uruchomić serwera”, tworząc przejrzysty zapis tego, co się stało i gdzie.
Wyzwanie
ŁatwyZbuduj system przetwarzania plików, który opakowuje błędy w informacje kontekstowe w miarę ich propagowania przez różne warstwy aplikacji. To wyzwanie pokazuje, jak używać specyfikatora formatu %w z funkcją fmt.Errorf, aby tworzyć łańcuchy błędów zachowujące pierwotny błąd i dodające istotny kontekst.
Otrzymasz dwa dane wejściowe:
- Ciąg znaków zawierający szczegóły operacji na pliku w formacie
"filename,operation,status"(np."config.json,read,permission_denied") - Ciąg znaków zawierający kontekst systemowy w formacie
"service_name,component"(np."UserService,ConfigLoader")
Twoje zadanie:
- Przeanalizuj pierwsze dane wejściowe, dzieląc je po przecinkach, aby uzyskać nazwę pliku, operację i status
- Przeanalizuj drugie dane wejściowe, dzieląc je po przecinkach, aby uzyskać nazwę usługi i komponent
- Utwórz pierwotny błąd na podstawie statusu, używając
errors.New():- Jeśli status to
"permission_denied":"permission denied" - Jeśli status to
"not_found":"file not found" - Jeśli status to
"corrupted":"file corrupted" - Dla każdego innego statusu:
"unknown error"
- Jeśli status to
- Utwórz opakowany błąd na poziomie pliku, używając
fmt.Errorfz%w:"failed to [operation] file [filename]: %w" - Utwórz opakowany błąd na poziomie komponentu:
"[component] error: %w" - Utwórz opakowany błąd na poziomie usługi:
"[service_name] operation failed: %w" - Wyświetl łańcuch błędów, wypisując każdy poziom:
"Original error: [original_error_message]""File level: [file_level_error_message]""Component level: [component_level_error_message]""Service level: [service_level_error_message]"
- Wyświetl podsumowanie łańcucha błędów:
"Error Chain Summary:""File: [filename]""Operation: [operation]""Component: [component]""Service: [service_name]""Root cause: [original_error_message]"
Użyj pakietu strings, aby podzielić ciągi wejściowe po przecinkach, pakietu errors, aby utworzyć pierwotny błąd, oraz pakietu fmt, aby utworzyć opakowane błędy. To wyzwanie pokazuje, jak opakowywanie błędów za pomocą %w tworzy przejrzystą ścieżkę kontekstu, gdy błędy przechodzą przez różne warstwy aplikacji, znacznie ułatwiając debugowanie.
Spróbuj swoich sił
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
// Wczytaj dane wejściowe
var fileDetails string
var systemContext string
fmt.Scanln(&fileDetails)
fmt.Scanln(&systemContext)
// Przeanalizuj dane wejściowe
fileInfo := strings.Split(fileDetails, ",")
filename := fileInfo[0]
operation := fileInfo[1]
status := fileInfo[2]
contextInfo := strings.Split(systemContext, ",")
serviceName := contextInfo[0]
component := contextInfo[1]
// TODO: Napisz swój kod poniżej
// Utwórz pierwotny błąd na podstawie statusu
// Utwórz błąd opakowany na poziomie pliku
// Utwórz błąd opakowany na poziomie komponentu
// Utwórz błąd opakowany na poziomie usługi
// Wyświetl każdy poziom błędu oraz 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