for ... range döngüsü, dilim (slice), harita (map), dizi veya dize (string) elemanları üzerinde kolayca geçiş yapmayı sağlar.
Örnek:
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) }
Ana incelik:
Değişkenler i, v, k vb. tüm döngülerde yeniden kullanılır! Bu, döngü içinde referansla geçerken veya range içinde goroutine çalıştırırken sık sık hata kaynağı olur.
Slice içinde bir goroutine başlatıp döngü değişkenini yakalarsak ne olur? Hatanın önüne nasıl geçebiliriz?
Cevap: Tipik bir hata meydana gelir: Goroutine içinde kullanılan döngü değişkenleri, döngü tamamlandıktan sonra son değeri alacaktır. Önlemek için yerel kopyalar oluşturmak gerekir:
nums := []int{1, 2, 3} for _, v := range nums { go func(val int) { fmt.Println(val) }(v) }
Hikaye
Bir projede, goroutine aracılığıyla bir slice'ı doldurmak için range kullanıldı, ancak döngü değişkenlerinin kopyaları oluşturulmadı. Tüm goroutineler, dizinin son değerini yazdırdı, bu da iş mantığını ciddi şekilde bozdu.
Hikaye
Map üzerinde range yaparken, değerlerin referansını yeni bir işaretçi dizisine kaydettik. Sonuç olarak, yeni dizinin tüm elemanları döngüde kullanılan aynı değişkene — değerinin kopyasına — referans oldu. Bu değişkenlerde döngü dışında güncelleme yapıldığında hata meydana geldi (panic: geçersiz bellek adresi veya beklenmeyen veriler).
Hikaye
Bir iç araçta string üzerinde range yaparak önemli alt dizeleri işleyen işleyicileri başlattım, ancak her bir döngü için baytlarda, Unicode karakterlerinde değil, kayma aldım. Sonuç: Unicode dizeleri için yanlış işleme, sembollerin yanlış şekilde kesilmesi.