ProgrammatieGo backend engineer

Leg uit hoe het range-mechanisme in Go werkt met maps en slices. Wat zijn de nuances van het gebruik van loopvariabelen en met welke fouten kun je te maken krijgen?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

De for ... range loop maakt het eenvoudig om door de elementen van een slice, map, array of string te itereren.

  • Voor slices: retourneert bij elke iteratie de index en een kopie van het element.
  • Voor maps: retourneert de sleutel en een kopie van de waarde.

Voorbeeld:

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) }

Belangrijke nuance: De variabelen i, v, k enz. worden hergebruikt in alle iteraties! Dit wordt vaak een bron van bugs wanneer ze als referentie binnen de loop worden doorgegeven of wanneer goroutines binnen de range worden gestart.

Misleidende vraag

Wat gebeurt er als je binnen een range over een slice een goroutine start, waarbij je de iteratievariabele vastlegt? Hoe kun je de fout vermijden?

Antwoord: Er ontstaat een typische fout: binnen de goroutine worden de loopvariabelen gebruikt, die na het beëindigen van de loop de laatste waarde zullen hebben. Om dit te vermijden, moet je lokale kopieën maken:

nums := []int{1, 2, 3} for _, v := range nums { go func(val int) { fmt.Println(val) }(v) }

Voorbeelden van echte bugs door onbekendheid met nuances


Verhaal

In een project werd range gebruikt om een slice in te vullen via meerdere goroutines, waarbij de loopvariabelen niet gekopieerd werden. Alle goroutines drukten dezelfde waarde af — de laatste uit de array, wat de bedrijfslogica ernstig verstoorde.


Verhaal

Bij range over een map werd de link naar de waarde opgeslagen in een nieuwe slice van pointers. Hierdoor verwezen alle elementen van de nieuwe slice naar dezelfde variabele — die gebruikt werd in de loop (kopie van de waarde). De bug manifesteerde zich bij het bijwerken van deze variabelen buiten de loop (panic: ongeldige geheugenadres of onverwachte gegevens).


Verhaal

In een interne tool startte ik handlers met een zware substring binnen range over een string, maar voor elke iteratie kreeg ik een offset in bytes in plaats van in Unicode-tekens. Resultaat: onjuiste verwerking voor Unicode-strings, onjuiste splitsing van tekens.