Die Schleife for ... range ermöglicht es, bequem über die Elemente eines Slices, einer Map, eines Arrays oder einer Zeichenkette zu iterieren.
Beispiel:
s := []int{1, 2, 3} for i, v := range s { fmt.Println(i, v) } m := map[string]int{"a":1, "b":2} for k, v := range m { fmt.Println(k, v) }
Wichtige Feinheit:
Die Variablen i, v, k usw. werden in allen Iterationen wiederverwendet! Dies wird häufig zur Quelle von Bugs, wenn sie innerhalb der Schleife per Referenz übergeben oder Goroutinen innerhalb von Range gestartet werden.
Was passiert, wenn man innerhalb von Range auf einem Slice eine Goroutine startet und die Iterationsvariable erfasst? Wie kann man den Fehler vermeiden?
Antwort: Es tritt ein typischer Fehler auf: Innerhalb der Goroutine werden die Schleifenvariablen verwendet, die nach Abschluss der Schleife den letzten Wert haben werden. Um dies zu vermeiden, sollte man lokale Kopien erstellen:
nums := []int{1, 2, 3} for _, v := range nums { go func(val int) { fmt.Println(val) }(v) }
Geschichte
In einem Projekt wurde Range verwendet, um einen Slice über mehrere Goroutinen zu füllen, ohne die Schleifenvariablen zu kopieren. Alle Goroutinen druckten denselben Wert aus – den letzten des Arrays, was die Geschäftslogik stark beeinträchtigte.
Geschichte
Beim Iterieren über eine Map wurde der Verweis auf den Wert in einen neuen Slice von Zeigern gespeichert. Infolgedessen verwiesen alle Elemente des neuen Slices auf dieselbe Variable – die, die in der Schleife verwendet wurde (Kopie des Wertes). Der Bug zeigte sich bei der Aktualisierung dieser Variablen außerhalb der Schleife (panic: ungültige Speicheradresse oder unerwartete Daten).
Geschichte
In einem internen Tool wurden beim Range über einen String Handler für gewichtige Teilstrings gestartet, aber für jede Iteration erhielt ich einen Offset in Bytes, nicht in Unicode-Zeichen. Ergebnis: fehlerhafte Verarbeitung für Unicode-Zeichen, fehlerhaftes Schneiden von Zeichen.