In Go worden de regels voor de zichtbaarheid van variabelen (scoping) strikt gedefinieerd door blokken ({}), en de naam van een variabele kan worden overschreven (shadowing) in geneste scopes. Vooral veel valkuilen ontstaan in geneste functies, anonieme functies, lussen en bij het declareren van variabelen met dezelfde naam op verschillende niveaus.
Go heeft speciaal "magisch" gedrag met betrekking tot scope geminimaliseerd om de code leesbaarder te maken. Maar de flexibiliteit van de syntaxis en de mogelijkheid om variabelen opnieuw te declareren met de korte notatie := leidt vaak tot misverstanden.
Als je in een geneste functie of in een loopblok een variabele declareert met dezelfde naam als op het hoogste niveau, zal de externe variabele niet toegankelijk zijn (geoverschaduwd - shadowed). In de meeste gevallen merkt de compiler dit niet en dit kan gemakkelijk leiden tot fouten, vooral bij het werken met closures. Een andere veelvoorkomende fout is het declareren van een nieuwe variabele in een if-blok of in de for-init, en vervolgens proberen deze buiten het blok aan te roepen.
Houd altijd rekening met de niveaus van de zichtbaarheid. Gebruik geen identieke variabelenamen in geneste blokken of anonieme functies zonder echte noodzaak, vermijd korte namen en wees voorzichtig met het gebruik van :=.
Voorbeeldcode:
package main import "fmt" func main() { x := 1 { x := 2 // overschaduwt x uit main() fmt.Println("Inner x:", x) } fmt.Println("Outer x:", x) for i := 0; i < 3; i++ { x := i // nieuw x wordt aangemaakt bij elke iteratie go func() { fmt.Println("Goroutine x:", x) }() } }
In dit voorbeeld wordt de externe variabele x niet gewijzigd, en wordt een nieuwe x binnen het blok aangemaakt. In de tweede lus wordt de variabele x vastgelegd in de geneste functie — het resultaat kan onverwacht zijn.
Belangrijke kenmerken:
:= binnen een blok maakt altijd een nieuwe variabele aan, zelfs als de externe al bestaat.1. Welke waarde van de variabele zal als laatste worden afgedrukt in het geneste blok bij shadowing?
De waarde van de externe variabele, omdat de interne variabele alleen binnen het blok bestaat.
2. Wat gebeurt er als je probeert te verwijzen naar een variabele die binnen een if/for-blok is gedeclareerd, buiten dit blok?
De compiler zal een foutmelding geven: de variabele is buiten de scope.
if true { y := 5 } fmt.Println(y) // fout
3. Hoe voorkom je een onverwachte waarde bij het maken van een goroutine in een loop over een variabele?
Door de variabele als parameter van de functie door te geven:
for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }
:= een al bestaande variabele zal wijzigen (het maakt een nieuwe aan).Een lus initieert meerdere goroutines voor parallelle verwerking, maar binnen de closure wordt de loopvariabele gebruikt zonder door te geven — alle goroutines werken met de "laatste" waarde ervan.
Voordelen:
Nadelen:
De loopvariabele doorgeven als parameter aan de closure — elke goroutine krijgt zijn eigen waarde.
Voordelen:
Nadelen: