Fehlerbehandlung in Go: try/catch und mehr von A bis Z

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Fehlerbehandlung in Go: Philosophie und Praxis



Im Gegensatz zu vielen modernen Sprachen verwendet Go (Golang) nicht das klassische try/catch-Konstrukt. Stattdessen folgen Go-Entwickler dem Ansatz „Fehler als Werte“ (errors as values). Dies macht den Code expliziter, vorhersagbarer und sicherer. In diesem Artikel analysieren wir alle Aspekte der Fehlerbehandlung in Go: von grundlegenden Mustern bis hin zu fortgeschrittenen Techniken mit defer, panic und recover.



1. Grundlagen: Fehler sind einfach Werte



In Go ist ein Fehler das Interface error mit der einzigen Methode Error() string. Jede Funktion, die fehlschlagen kann, gibt einen Fehler als letzten Rückgabewert zurück.



package main

import ( "errors" "fmt")

// Divisionsfunktion mit Fehlerrückgabefunc divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("Division durch Null nicht möglich") } return a / b, nil}

func main() { result, err := divide(10, 0) if err != nil { fmt.Println("Fehler:", err) return } fmt.Println("Ergebnis:", result)}


Der entscheidende Punkt: Die Überprüfung if err != nil ist die Standardmethode zur Fehlerbehandlung in Go. Es gibt keine versteckten Ausnahmen, die unerwartet „auftauchen“ könnten.



2. Erstellung und Anpassung von Fehlern



Go bietet mehrere Möglichkeiten zur Fehlererstellung:



  • errors.New() — einfacher textueller Fehler.
  • fmt.Errorf() — formatierter Fehler (unterstützt %w für Wrapping).
  • Benutzerdefinierte Typen — zur Übergabe zusätzlichen Kontexts.


Benutzerdefinierter Fehler mit zusätzlichen Daten



type DivisionError struct {    Dividend float64    Divisor  float64    Message  string}

func (e *DivisionError) Error() string { return fmt.Sprintf("%s: %f / %f", e.Message, e.Dividend, e.Divisor)}

func safeDivide(a, b float64) (float64, error) { if b == 0 { return 0, &DivisionError{ Dividend: a, Divisor: b, Message: "Division durch Null", } } return a / b, nil}

func main() { _, err := safeDivide(10, 0) if err != nil { // Type Assertion zum Abrufen zusätzlicher Felder var divErr *DivisionError if errors.As(err, &divErr) { fmt.Printf("Fehler mit %f durch %f: %s", divErr.Dividend, divErr.Divisor, divErr.Message) } }}


Die Verwendung von errors.As() ermöglicht es zu prüfen, ob ein Fehler einem bestimmten Typ entspricht, und Daten daraus zu extrahieren. Dies ist das Äquivalent zu instanceof in anderen Sprachen.



3. Fehlerbehandlungsmuster: Vom Einfachen zum Komplexen



In Go gibt es mehrere etablierte Muster für die Arbeit mit Fehlern:



3.1. Sentinel-Fehler (Markierungsfehler)

Dies sind vordefinierte Fehler, die mit == verglichen werden können. Beispiel: io.EOF.



import (    "errors"    "fmt")

var ErrNotFound = errors.New("Element nicht gefunden")

func findUser(id int) (string, error) { if id != 1 { return "", ErrNotFound } return "Alice", nil}

func main() { _, err := findUser(2) if errors.Is(err, ErrNotFound) { fmt.Println("Benutzer nicht gefunden, erstelle neuen...") }}


3.2. Fehler-Wrapping (Umhüllen)

Seit Go 1.13 können Fehler mit %w in fmt.Errorf umhüllt werden. Dies bewahrt die Fehlerkette.



func readConfig(path string) error {    data, err := os.ReadFile(path)    if err != nil {        return fmt.Errorf("Lesen der Konfiguration %s: %w", path, err)    }    // ... Verarbeitung von data                

Blogs

Buchempfehlungen