⚠️ 1. Fehler sind normale Werte (Values)
In Go gibt es kein try / catch. Das eingebaute Interface error ist verblüffend einfach definiert:
type error interface {
Error() string
}
Jede Funktion, die fehlschlagen kann, gibt als letzten Wert ein error zurück. Der Aufrufer prüft diesen explizit:
data, err := os.ReadFile("config.yaml")
if err != nil {
// Fehlerbehandlung: Protokollieren, Wrappen oder Beenden
log.Fatalf("Konnte Konfiguration nicht laden: %v", err)
}
Ein Exception-System gleicht einem Rauchmelder, der das gesamte Gebäude evakuiert, wenn irgendwo ein Brötchen anbrennt. Gos if err != nil gleicht einem Boardingpass-Scanner am Gate: Jeder Passagier wird an jedem Kontrollpunkt einzeln und ruhig geprüft. Kein Passagier rutscht unbemerkt durch!
🔗 2. Sentinel Errors & Error Wrapping (%w)
Vordefinierte Fehlerkonstanten heißen Sentinel Errors (z.B. ErrNotFound). Mit fmt.Errorf("%w", err) können Fehler um Kontext angereichert werden, ohne die Fehlerursache zu verlieren:
var ErrAccountLocked = errors.New("benutzerkonto ist gesperrt")
func Authenticate(user string) error {
if isLocked(user) {
return ErrAccountLocked
}
if err := verifyPassword(user); err != nil {
// Fehler mit '%w' wrappen:
return fmt.Errorf("auth fehler für %s: %w", user, err)
}
return nil
}
🛠️ 3. Eigene Error-Structs für strukturierte Daten
Benötigt ein Fehler strukturierte Metadaten (wie HTTP-Statuscode oder Endpunkt), implementieren wir ein Custom Struct mit der Error() string Methode:
type APIError struct {
StatusCode int
Endpoint string
Message string
}
func (e *APIError) Error() string {
return fmt.Sprintf("API-Fehler [%d] bei %s: %s", e.StatusCode, e.Endpoint, e.Message)
}