Go'da anonim fonksiyonlar (function literals, closures) fonksiyonel stili, geri çağırmaları ve algoritmaların sade bir şekilde kapsüllenmesini desteklemek için ortaya çıkmıştır. Genellikle koleksiyonların işlenmesi, asenkron görevler için ve parametre olarak iletilmek üzere kullanılır.
Anonim fonksiyonlar olmadan kod gereksiz hale gelir: Her bir işleme ayrı bir isimlendirilmiş fonksiyona taşınmak zorundadır. Ancak, bu kullanımda bazı sorular ortaya çıkar: "değişkenlerin yakalanması" nasıl çalışır, bellek nerede saklanır, argüman olarak bildirimde ve geçişte hangi detaylar vardır? Dışarıdan değiştirildiğinde değişkenlerin yakalanması korunuyor mu? En yaygın hata, döngüdeki değişkenin yanlış şekilde yakalanmasıdır.
Anonim fonksiyonlar, literal olarak tanımlanır ve değişkenlere atanabilir veya doğrudan kullanılabilir. Eğer anonim bir fonksiyon dış alanın değişkenlerine erişiyorsa, bu değişkenler "yakalanır" ve closure'ın yaşam süresi için saklanır. Fonksiyon parametresi olarak, anonim fonksiyon genellikle fonksiyonun imzası ile uyumlu bir func tipi ile geçirilir. En büyük problemler döngü değişkenlerinin yakalanması sırasında oluşur — burada, eğer mantığı bir closure içine sarmak gerekiyorsa, mutlaka döngü içinde yeni bir değişken oluşturmalısınız.
Kod örneği:
func operate(nums []int, op func(int) int) []int { res := make([]int, len(nums)) for i, n := range nums { res[i] = op(n) } return res } func main() { arr := []int{1, 2, 3} out := operate(arr, func(x int) int {return x * x}) fmt.Println(out) // [1 4 9] }
Anahtar özellikler:
Bir döngüde değişkenin değişken değerinin yakalanması durumunda ne olur?
Tüm closure'lar aynı değişkeni yakalayacak ve döngü sonrası fonksiyon çağrısı yaptığınızda aynı değeri alacaksınız.
Kod örneği:
func main() { a := []func(){} for i := 0; i < 3; i++ { a = append(a, func() { fmt.Println(i) }) } for _, f := range a { f() } // 3 3 3 }
Bunu önlemek için döngü gövdesinde yeni bir değişken oluşturmalısınız:
for i := 0; i < 3; i++ { j := i a = append(a, func() { fmt.Println(j) }) // 0 1 2 }
Anonim fonksiyonlar interface{} türü değerleri olarak kullanılabilir mi?
Fonksiyonlar yalnızca interface{} ile uyumludur, diğer arayüzlerle değil, birbirleriyle karşılaştırılamazlar (nil dışında). Eğer bir closure'ı interface{} olarak geçirirseniz, sadece fonksiyon imzasına tür dönüşümü ile çağırabilirsiniz.
Anonim fonksiyonlar özyinelemeli olabilir mi?
Evet, ancak öncelikle closure için bir isim değişkeni tanımlanmalı ve ardından fonksiyon ona atanmalıdır.
Kod örneği:
var fib func(n int) int fib = func(n int) int { if n < 2 { return n } return fib(n-1) + fib(n-2) } fmt.Println(fib(10)) // 55
Geri çağırmaların listesi üzerinde döngüde geliştirici, işleyiciyi döngü değişkeni ile bir closure olarak bağlar. Tüm geri çağırmalar uyumsuz bir değerle çalışır ve hatalara yol açar.
Artılar:
Eksiler:
Her bir closure için döngü içinde yeni bir değişken oluşturulur, değerlerin doğru yakalandığından ve beklenen davranışın sağlandığından emin olunur.
Artılar:
Eksiler: