Go'da değişkenlerin kapsam kuralları (scoping) bloklar ({}) ile katı bir şekilde belirlenir ve bir değişkenin adı iç içe alanlarda gölgelenebilir (shadowing). Özellikle iç içe fonksiyonlar, anonim fonksiyonlar, döngüler ve farklı seviyelerde aynı isimle değişkenler tanımlandığında birçok tuzak ortaya çıkar.
Go, kodun okunabilirliğini artırmak için kapsam ile ilgili "büyülü" davranışları en aza indirmiştir. Ancak, sentez esnekliği ve kısa biçimle değişkenlerin yeniden tanımlanmasına izin verilmesi, algıda hatalara yol açmaktadır.
Eğer bir iç içe fonksiyonda veya bir döngü bloğunda üst seviyedekiyle aynı isme sahip bir değişken tanımlanırsa, dıştaki değişken erişilemez (gölgelendi — shadowed) olur. Çoğu durumda bu, derleyici tarafından fark edilmez ve özellikle closure ile çalışırken hatalara neden olabilir. Bir diğer yaygın hata, bir if bloğunda veya for-init içinde yeni bir değişken tanımlamak ve ardından bu değişkene blok dışında erişmeye çalışmaktır.
Her zaman kapsam seviyelerine dikkat edin. İç içe bloklarda veya anonim fonksiyonlarda gerçek bir ihtiyaç olmadan aynı değişken isimlerini kullanmaktan kaçının, kısa isimler kullanmayın ve := kullanırken dikkatli olun.
Kod örneği:
package main import "fmt" func main() { x := 1 { x := 2 // main()'den x'i gölgeler fmt.Println("İç x:", x) } fmt.Println("Dış x:", x) for i := 0; i < 3; i++ { x := i // her iterasyonda yeni bir x oluşturulur go func() { fmt.Println("Goroutine x:", x) }() } }
Bu örnekte dıştaki değişken x değişmezken, iç blokta yeni bir x oluşturulmaktadır. İkinci döngüde x değişkeni içteki fonksiyon tarafından yakalanır — sonuç beklenmedik olabilir.
Anahtar özellikler:
:= kısa biçimi her zaman yeni bir değişken oluşturur, dışarıda bir değişken olsa bile.1. Gölgeleme durumunda iç blokta son olarak hangi değişkenin değeri yazdırılacak?
Dıştaki değişkenin değeri, çünkü içteki değişken sadece blok içinde var olur.
2. Eğer bir blok içinde tanımlanan bir değişkene, o bloğun dışında erişmeye çalışırsanız ne olur?
Derleyici hata verecektir: değişken kapsam dışındadır.
if true { y := 5 } fmt.Println(y) // hata
3. Değişkeni döngüde goroutine oluştururken beklenmedik bir değer almaktan nasıl kaçınılır?
Değişkeni fonksiyonun parametresi olarak geçirerek:
for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }
:='in mevcut bir değişkeni değiştireceğini beklemek (yeni bir değişken oluşturur).Döngü, paralel işleme için birkaç goroutine başlatır, ancak closure içinde döngü değişkeni kullanılmadan geçilmektedir — tüm goroutine'ler onun "son" değeriyle çalışmaktadır.
Artıları:
Eksileri:
Döngü değişkeninin closure parametresi olarak geçirilmesi — her goroutine kendi değerini alır.
Artıları:
Eksileri: