Darsliklar Go Lang Defer

Go Lang Go Lang Defer

Defer — Go’ga xos, boshqa ko’p tillarda to’g’ridan-to’g’ri analogi bo’lmagan kalit so’z. U funksiya chaqiruvini hozir emas, o’zini o’rab turgan funksiya tugashidan oldin bajarilishga “kechiktiradi” — resurslarni tozalash (fayl yopish, ulanishni uzish) uchun ideal vosita.

deferdefer bilan belgilangan funksiya chaqiruvi darhol emas, uni o’rab turgan funksiya return qilishidan bir zum oldin bajariladi. Argumentlar esa defer yozilgan paytning o’zida hisoblanadi.

Asosiy ishlash tartibi

package main

import "fmt"

func main() {
    fmt.Println("Fayl ochildi")
    defer fmt.Println("Fayl yopildi")
    fmt.Println("Fayl bilan ishlanmoqda")
}
Fayl ochildi
Fayl bilan ishlanmoqda
Fayl yopildi

defer fmt.Println("Fayl yopildi") yozilgan joyida emas, main tugashidan oldin ishga tushdi — garchi u kod bo’yicha ikkinchi qatorda tursa ham, natijada oxirgi bo’lib chop etildi.

Bir nechta defer — teskari tartibda (LIFO)

Bitta funksiyada bir nechta defer bo’lsa, ular teskari — oxirgi e’lon qilingani birinchi bo’lib — ishga tushadi:

package main

import "fmt"

func main() {
    fmt.Println("Boshlanishi")
    defer fmt.Println("Birinchi defer")
    defer fmt.Println("Ikkinchi defer")
    defer fmt.Println("Uchinchi defer")
    fmt.Println("Tugashi")
}
Boshlanishi
Tugashi
Uchinchi defer
Ikkinchi defer
Birinchi defer

Uchta defer steka (LIFO — Last In, First Out) tamoyili bilan yig’iladi: oxirgi qo’shilgani (“Uchinchi”) birinchi bajariladi. Bu, masalan, bir nechta resurs ochilganda, ularni ochilishga teskari tartibda yopish uchun tabiiy mos keladi.

Argument darhol hisoblanadi, chaqiruv esa kechiktiriladi

Nozik, lekin muhim jihat: deferga uzatilgan argumentning qiymati shu qatorning o’zida, hisoblanadi — funksiya esa keyinroq, o’sha “muzlatilgan” qiymat bilan chaqiriladi:

package main

import "fmt"

func main() {
    son := 1
    defer fmt.Println("Deferdagi qiymat:", son)
    son = 100
    fmt.Println("Joriy qiymat:", son)
}
Joriy qiymat: 100
Deferdagi qiymat: 1

defer fmt.Println(..., son) yozilgan paytda son1 edi, aynan shu qiymat “eslab qolindi”. Keyinroq son = 100 deb o’zgartirilgan bo’lsa-da, deferlangan chaqiruv baribir eski, 1 qiymatini ko’rsatdi.

Amaliy foydalanish — resursni yopish

deferning eng keng tarqalgan qo’llanilishi — resurs ochilgan joyning o’zida, uni yopish kodini ham darhol yozish, shunda uni unutib qo’yish deyarli mumkin emas:

package main

import "fmt"

func amalBajar() {
    fmt.Println("Boshlash")
    defer fmt.Println("Tozalash")

    fmt.Println("1-qadam")
    fmt.Println("2-qadam")
}

func main() {
    amalBajar()
    fmt.Println("Dastur tugadi")
}
Boshlash
1-qadam
2-qadam
Tozalash
Dastur tugadi

defer fmt.Println("Tozalash") funksiya boshida yozilgan bo’lsa-da, u amalBajar ichidagi barcha qadamlardan keyin, lekin amalBajar chaqiruvchiga qaytishidan oldin ishladi. Haqiqiy kodda bu o’rinda odatda fayl.Close() yoki ulanish.Yopish() kabi chaqiruv turadi.