Yopilishlar
Go dasturlash tilida closure (yopilish) — bu tashqi funksiya o'z ishini yakunlagan bo'lsa ham, uning ichidagi o'zgaruvchilarga murojaat qilish imkoniyatini saqlab qoluvchi ichki (ichma-ich) funksiyadir.
Closure tushunchasini to'liq anglash uchun dastlab ikkita muhim jihatni ko'rib chiqamiz:
Go tilida bitta funksiya ichida boshqa bir anonim funksiyani yaratish mumkin:
package main
import "fmt"
// Tashqi funksiya
func greet(name string) {
// Ichki funksiya
var displayName = func() {
fmt.Println("Salom", name)
}
// Ichki funksiyani chaqiramiz
displayName()
}
func main() {
greet("Ali") // Salom Ali
}
Funksiya o'zidan anonim funksiyani qaytarishi mumkin:
package main
import "fmt"
func greet() func() {
return func() {
fmt.Println("Salom Ali")
}
}
func main() {
// g1 o'zgaruvchisi qaytgan funksiyani qabul qiladi
g1 := greet()
// Funksiyani chaqiramiz
g1()
}
Natija:
Salom Ali
Oddiy holatda funksiya ishlab bo'lgach, uning mahalliy o'zgaruvchilari xotiradan o'chiriladi. Ammo closure yaratilganda, ichki funksiya tashqi funksiyaning o'zgaruvchisini o'z doirasida "yopib" (saqlab) oladi:
package main
import "fmt"
// Tashqi funksiya
func greet() func() string {
// Tashqi o'zgaruvchi
name := "Ali"
// Ichki anonim funksiyani qaytaramiz
return func() string {
name = "Salom " + name
return name
}
}
func main() {
// Tashqi funksiyani chaqiramiz
message := greet()
// Ichki funksiyani chaqiramiz
fmt.Println(message())
}
Natija:
Salom Ali
Bu yerda greet() o'z ishini tugatgan bo'lsa-da, message() ichidagi funksiya name o'zgaruvchisiga kirish huquqini saqlab qoldi.
Closure orqali funksiya chaqirilganda o'zgaruvchi holatini (state) saqlab borish juda qulay:
package main
import "fmt"
func calculate() func() int {
num := 1
// Har chaqirilganda num qiymatini 2 ga oshirib boradi
return func() int {
num = num + 2
return num
}
}
func main() {
odd := calculate()
fmt.Println(odd()) // 3
fmt.Println(odd()) // 5
fmt.Println(odd()) // 7
// Yangi closure yaratamiz
odd2 := calculate()
fmt.Println(odd2()) // 3
}
Natija:
3
5
7
3
Har safar tashqi funksiya chaqirilganda, u yangi va mustaqil closure nusxasini qaytaradi. Bir nechta closure nusxalari bir-birining qiymatiga mutlaqo ta'sir qilmaydi:
package main
import "fmt"
func displayNumbers() func() int {
number := 0
return func() int {
number++
return number
}
}
func main() {
// Birinchi closure
num1 := displayNumbers()
fmt.Println(num1()) // 1
fmt.Println(num1()) // 2
fmt.Println(num1()) // 3
// Ikkinchi mustaqil closure
num2 := displayNumbers()
fmt.Println(num2()) // 1
fmt.Println(num2()) // 2
}
Natija:
1
2
3
1
2
num1 chaqirilganda number o'zgaruvchisi 3 ga yetdi, lekin yangi yaratilgan num2 mutlaqo yangi xotira bilan 1 dan boshlandi. Bu dasturlashda ma'lumotlarni xavfsiz va alohida (izolyatsiyalangan) saqlashda juda qo'l keladi.