Top-Fehler von Go-Anfängern: Fortgeschrittenes Niveau

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

Einleitung

Go (Golang) ist bekannt für seine Einfachheit und Prägnanz. Hinter der scheinbaren Leichtigkeit verbergen sich jedoch Fallstricke, die besonders tückisch für Entwickler sind, die bereits die Syntax und grundlegenden Konstrukte beherrschen. Der Übergang zum "fortgeschrittenen" Niveau bedeutet nicht, komplexe Muster zu kennen, sondern ein tiefes Verständnis der Laufzeitumgebung, der Typen und der Nebenläufigkeit zu haben.

In diesem Artikel analysieren wir die Top-Fehler von Go-Anfängern, die über "vergessen, eine Datei zu schließen" oder "nil mit einem Fehler verwechselt" hinausgehen. Sie erfahren, wie Sie Speicherlecks, falsche Arbeit mit Goroutinen und Kanälen vermeiden, und verstehen, warum nil nicht immer nil ist.



Fehler 1: Goroutine-Leaks

Der teuerste Fehler in Go ist es, eine Goroutine zu starten und sie zu vergessen. Anfänger denken oft, dass die Goroutine von selbst endet, sobald die Funktion ausgeführt wird. Aber wenn eine Goroutine an einem Kanal blockiert, der niemals Daten erhält, hängt sie für immer fest.



Problem: Vergessener Kanal ohne Empfänger

func process(data []int) chan int {    out := make(chan int)    go func() {        for _, v := range data {            out <- v * 2        }        close(out)    }()    return out}

func main() { ch := process([]int{1, 2, 3}) // Lesen nur einen Wert, der Kanal wird nicht geschlossen fmt.Println(<-ch) // Die Goroutine hängt fest und versucht, 4 und 6 an den Kanal zu senden // time.Sleep(time.Second) — Speicherleck}

Lösung: Kontrollieren Sie immer die Lebensdauer der Goroutine. Verwenden Sie context.Context zum Abbrechen oder gepufferte Kanäle, wenn Sie sich über die Anzahl der Leser nicht sicher sind.



func process(ctx context.Context, data []int) <-chan int {    out := make(chan int)    go func() {        defer close(out)        for _, v := range data {            select {            case out <- v * 2:            case <-ctx.Done():                return            }        }    }()    return out}


Fehler 2: Falsche Verwendung von select mit default

Die select-Anweisung mit default ist ein mächtiges Werkzeug für nicht-blockierende Operationen. Aber Anfänger verwenden sie oft als "Krücke", was zu einer Busy-Loop (Endlosschleife mit hoher CPU-Auslastung) führt.



Problem: Endlosschleife ohne Blockierung

for {    select {    case msg := <-ch:        fmt.Println(msg)    default:        // Nichts tun, aber die Schleife blockiert nicht    }}

Dieser Code wird den Prozessor stark belasten und 100% eines Kerns verbrauchen. default macht select nicht-blockierend, und die Schleife wird zu einer Endlosabfrage.

Lösung: Entweder entfernen Sie default (dann wartet select), oder fügen Sie time.Sleep oder time.Tick hinzu, um die Last zu reduzieren.



// Richtige Variante: ohne defaultfor msg := range ch {    fmt.Println(msg)}

// Oder mit Timeoutfor { select { case msg := <-ch: fmt.Println(msg) case <-time.After(100 * time.Millisecond): // Periodische Überprüfung }}


Fehler 3: nil-Interface ist nicht nil

Dies ist eine klassische Falle in Go. Eine Variable vom Typ interface{} ist nur dann gleich nil, wenn sowohl ihr Typ als auch ihr Wert nil sind. Wenn Sie dem Interface einen Zeiger auf nil zuweisen, ist das Interface nicht mehr nil.



Problem: Prüfung auf nil über ein Interface

type MyError struct{}

func (e *MyError) Error() string { return "Fehler"}

func getError() error { var e *MyError = nil return e // Gibt einen nil-Zeiger zurück, aber der Typ ist nicht nil}

func main() { err := getError() if err != nil { fmt.Println("Es gibt einen Fehler!")

Blogs

Buchempfehlungen