Go'da closure'lar (kapalı fonksiyonlar), bulundukları kapsama alanındaki değişkenleri "kaplayan" (yakalanan) fonksiyonlardır. En sık olarak arallik fonksiyonlar için, diğer fonksiyonların içinde oluşturulan kapanışlar kullanılır.
Closure'larla çalışırken en yaygın sorun, döngü değişkenlerinin goroutine içinde kullanılması sırasında beklenmedik davranıştır:
for i := 0; i < 3; i++ { go func() { fmt.Println(i) }() }
Her bir goroutine, aynı i değerini yazdırabilir çünkü değişken i döngüdür ve closure, değişkeni değil, her bir iterasyondaki değerini yakalar.
Doğru yol:
for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }
Bu davranış, closure'ın değişkenin referansını (adresini) tutmasından kaynaklanır, kesilmiş değerini (by value) değil.
Bir döngü içinde başlatılan birkaç goroutine, döngü değişkenini yakaladıklarında hangi değeri yazdıracaklar?
Cevap: Tüm goroutine'ler aynı değeri (genellikle son değeri) yazdırabilir çünkü güncel değişken değerini görürler ve goroutine'ler çalışmaya başladığında döngü zaten tamamlanmıştır. Bu durumdan kaçınmak için değişkenin, closure'a parametre olarak geçirilmesi gerekir.
Örnek:
for i := 0; i < 5; i++ { go func() { fmt.Println(i) }() } // büyük ihtimalle: 5 5 5 5 5 alırız
Hikaye
Hikaye
Hikaye
Bir kargo girişiminde, closure'ların sipariş koordinatlarını güncellerken hatalı kullanımı, kesitteki son siparişin koordinatlarının topluca güncellenmesine, o anki koordinatların yerine geçmesine neden oldu - anonim fonksiyon içinde kesite erişim nedeniyle yarış durumundan dolayı.