Tarkibga o'tish

5. Xatolar, defer, panic va recover

Go'da xato — oddiy qiymat (error interfeysi). Barcha masalalarda xatoni e'tiborsiz qoldirmang: uni qayta ishlang yoki kontekst qo'shib yuqoriga qaytaring.

Xato qaytarish va tekshirish

1. Divide(a, b float64) (float64, error) funksiyasini yozing: b == 0 bo'lganda errors.New bilan xato qaytarsin. Chaqiruvchi tomonda xatoni tekshirib, mos xabar chiqaring.
Misol: Divide(10, 2) → 5 <nil>; Divide(1, 0) → 0 va xato «nolga bo'lish mumkin emas»

2. Foydalanuvchi kiritgan satrni strconv.Atoi bilan songa aylantiring. Xato bo'lganda *strconv.NumError turidagi xato ichidagi ma'lumotlarni (Func, Num, Err) chiqaring.
Misol: "12a" → Func = Atoi, Num = 12a, Err = invalid syntax

3. Qo'riqchi (sentinel) xatolar: ErrNotFound va ErrPermission ni e'lon qiling. Find(id int) (User, error) funksiyasi ulardan birini qaytarsin; chaqiruvchi errors.Is bilan xato turini aniqlasin.
Misol: Find(1) → muvaffaqiyatli; Find(2) → ErrNotFound, errors.Is(err, ErrNotFound) → true

4. fmt.Errorf("foydalanuvchini o'qish: %w", err) yordamida xatoga kontekst qo'shing. Uch darajali chaqiruvlar zanjirida xato xabari qanday yig'ilishini ko'rsating va errors.Unwrap bilan asl xatoni oling.
Misol: foydalanuvchini o'qish: bazaga ulanish: connection refused; errors.Unwrap → bazaga ulanish: connection refused

5. Maxsus xato turi ValidationError{Field string; Reason string} ni yarating. Uni o'ralgan (wrapped) holda qaytaring va chaqiruvchida errors.As bilan ajratib oling.
Misol: ValidationError{"email", "noto'g'ri format"} o'ralgan holda qaytarilsa → errors.As → Field = email

6. Bir nechta xatoni birlashtiring (errors.Join): formadagi barcha noto'g'ri maydonlar haqidagi xatolarni to'plab, bitta xato sifatida qaytaring va har birini alohida chiqaring.
Misol: errors.Join(errors.New("ism bo'sh"), errors.New("yosh manfiy")) → ism bo'sh va yosh manfiy (har biri alohida qatorda)

7. %w va %v bilan o'ralgan xatolarni solishtiring: qaysi holatda errors.Is asl xatoni topa oladi?
Misol: fmt.Errorf("...: %w", ErrX) → errors.Is(err, ErrX) → true; %v bilan → false

defer

8. Funksiyada uchta defer e'lon qiling va ularning bajarilish tartibini (LIFO) ko'rsating.
Misol: defer "1", defer "2", defer "3" → 3 2 1

9. defer fmt.Println(i) da argument qachon hisoblanishini ko'rsating: sikl ichida defer va closure orqali defer natijalarini solishtiring.
Misol: x := 1; defer fmt.Println("arg:", x); defer func() { fmt.Println("closure:", x) }(); x = 2 → closure: 2, arg: 1

10. Faylni ochib, defer f.Close() bilan yopuvchi funksiya yozing. Close qaytargan xatoni ham e'tiborsiz qoldirmaslik uchun nomlangan natija (err error) va defer dan foydalaning.
Misol: mavjud fayl → Close xatosiz; Close xato qaytarsa, nomlangan err orqali chaqiruvchiga yetib boradi

11. defer yordamida funksiyaning bajarilish vaqtini o'lchang: defer timer("hisoblash")() naqshini amalga oshiring.
Misol: defer timer("hisoblash")() → hisoblash: 1.2ms (vaqt har safar boshqacha)

12. Nomlangan natija qiymatini defer ichida o'zgartirish mumkinligini ko'rsating: funksiya qaytaradigan qiymatni defer orqali ikki baravar oshiring.
Misol: func f() (n int) { defer func() { n *= 2 }(); return 5 } → 10

panic va recover

13. Slice chegarasidan tashqariga chiqish, nil map'ga yozish va nil ko'rsatkichga murojaat — uchala holatda ham yuzaga keladigan panic xabarlarini ko'rsating.
Misol: s := []int{1, 2, 3}; _ = s[5] → index out of range [5] with length 3; nil map'ga yozish → assignment to entry in nil map; nil ko'rsatkich → invalid memory address or nil pointer dereference

14. SafeDivide(a, b int) (res int, err error) funksiyasini yozing: butun songa nolga bo'lishda yuz beradigan panic ni recover bilan ushlab, xatoga aylantirsin.
Misol: SafeDivide(10, 2) → 5 <nil>; SafeDivide(1, 0) → 0 va xato runtime error: integer divide by zero

15. recover faqat defer qilingan funksiya ichida ishlashini ko'rsating: oddiy chaqiruvda u nil qaytaradi.
Misol: recover() oddiy chaqiruvda → nil; defer func() { r := recover() ... }() ichida → panic qiymati

16. Vazifalar ro'yxatini bajaruvchi funksiya yozing: bitta vazifa panic bersa ham, qolganlari bajarilaversin va har bir vazifa natijasi (muvaffaqiyat yoki xato) chiqarilsin.
Misol: [ok, panic("xato"), ok] → 1: muvaffaqiyat, 2: xato, 3: muvaffaqiyat

17. panic va error dan qachon foydalanish kerakligini misol bilan ko'rsating: MustParse(s string) Config (ishga tushishdagi xato — panic) va Parse(s string) (Config, error).
Misol: Parse("noto'g'ri") → Config{} va xato; MustParse("noto'g'ri") → panic

Amaliy masalalar

18. Konfiguratsiya faylini (kalit=qiymat) o'qiydigan funksiya yozing. Har bir xato qator raqami va sababi bilan qaytarilsin (config.txt:12: '=' belgisi yo'q).
Misol: config.txt: port=8080, host → config.txt:2: '=' belgisi yo'q

19. Bank o'tkazmasi: Transfer(from, to *Account, sum int) error funksiyasi mablag' yetmaganda ErrInsufficientFunds, hisob bloklanganda *AccountLockedError qaytarsin. Chaqiruvchi har bir holatni alohida qayta ishlasin.
Misol: balans 100, Transfer(..., 200) → ErrInsufficientFunds; hisob bloklangan bo'lsa → *AccountLockedError

20. Qayta urinish (retry) funksiyasini yozing: Retry(attempts int, delay time.Duration, fn func() error) error. Vaqtinchalik xatolarda qayta urinsin, doimiy xatoda (ErrPermanent bilan o'ralgan) darhol to'xtasin.
Misol: fn ikki marta vaqtinchalik xato, uchinchida muvaffaqiyat → 3 urinish, nil; ErrPermanent bilan o'ralgan xato → 1 urinish, xato qaytariladi