errors paketi: chuqurroq nazar
Golang'ning "Errors" darsida errors.New() va shaxsiy xatolik turlarini yaratishning asosini ko'rgan edik. Bu darsda errors paketining ancha kuchli imkoniyatlariga to'xtalamiz: xatoliklarni "o'rash" (wrapping), ma'lum bir xatolikni aniqlash (Is) va undan ma'lumot olish (As), hamda bir nechta xatolikni birlashtirish (Join).
Bu imkoniyatlar ayniqsa katta dasturlarda, xatolik bir funksiyadan ikkinchisiga "ko'tarilib" borganda, dastlabki sababni yo'qotmasdan uzatish uchun juda muhim.
import "errors"
%wFunksiya ichida xatolik yuz berganda, uni "yalang'och" holda emas, balki qo'shimcha kontekst bilan birga qaytarish foydali. fmt.Errorf()dagi maxsus %w format spetsifikatori aynan shu uchun mo'ljallangan — u asl xatolikni yangisi ichiga "o'raydi":
package main
import (
"errors"
"fmt"
)
// paket darajasidagi, oldindan e'lon qilingan xatolik
var ErrNotFound = errors.New("topilmadi")
func findUser(id int) error {
if id == 0 {
// %w orqali ErrNotFound'ni yangi xabar ichiga o'raymiz
return fmt.Errorf("foydalanuvchi qidirishda xatolik: %w", ErrNotFound)
}
return nil
}
func main() {
err := findUser(0)
fmt.Println(err)
}
Natija:
foydalanuvchi qidirishda xatolik: topilmadi
[!IMPORTANT]
%wbilan%v(yoki%s) orasidagi farq muhim:%vxatolikni shunchaki matn sifatida "yopishtirib qo'yadi" va asl xatolik haqidagi ma'lumot yo'qoladi.%wesa asl xatolikni ichida saqlab qoladi, shuning uchun keyinroq unierrors.Is()/errors.As()orqali qayta tiklash mumkin bo'ladi.
errors.Is()Agar funksiya "o'ralgan" xatolik qaytargan bo'lsa, uning ichida ma'lum bir xatolik (masalan, ErrNotFound) bor-yo'qligini == orqali emas, errors.Is() orqali tekshiramiz:
package main
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("topilmadi")
func findUser(id int) error {
if id == 0 {
return fmt.Errorf("foydalanuvchi qidirishda xatolik: %w", ErrNotFound)
}
return nil
}
func main() {
err := findUser(0)
// err "yopilgan" xabar bo'lsa ham, ichida ErrNotFound borligini topadi
if errors.Is(err, ErrNotFound) {
fmt.Println("Foydalanuvchi topilmadi!")
}
}
Natija:
Foydalanuvchi topilmadi!
[!WARNING]
err == ErrNotFoundyozish ishlamaydi, chunkierr— bufmt.Errorf()yaratgan YANGI xatolik obyekti,ErrNotFoundning o'zi emas (u faqat ichiga "o'ralgan"). Shu sababli "o'ralgan" xatoliklarni solishtirish uchun har doimerrors.Is()ishlatilishi shart.
errors.As()Agar xatolik oddiy matn emas, balki qo'shimcha ma'lumotga ega maxsus tur (struct) bo'lsa va o'sha ma'lumotga (masalan, qaysi maydon xato ekanligiga) kirish kerak bo'lsa — errors.As() ishlatiladi:
package main
import (
"errors"
"fmt"
)
// shaxsiy xatolik turi, qo'shimcha ma'lumot (Field) bilan
type ValidationError struct {
Field string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s maydoni noto'g'ri", e.Field)
}
func validate() error {
return &ValidationError{Field: "email"}
}
func main() {
err := validate()
var valErr *ValidationError
// agar err (yoki ichiga o'ralgan xatolik) *ValidationError bo'lsa,
// uni valErr o'zgaruvchisiga "chiqarib" beradi
if errors.As(err, &valErr) {
fmt.Println("Muammoli maydon:", valErr.Field)
}
}
Natija:
Muammoli maydon: email
errors.As() — bu, aslida, oddiy type assertion (err.(*ValidationError))ning "chuqurroq" versiyasi: u nafaqat errning o'zini, balki uning ichiga o'ralgan barcha xatoliklar zanjirini ham tekshirib chiqadi.
errors.Unwrap()Agar o'ralgan xatolik ichidagi asl xatolikni to'g'ridan-to'g'ri olish kerak bo'lsa (kamdan-kam holatlarda kerak bo'ladi, odatda Is/As yetarli):
package main
import (
"errors"
"fmt"
)
func main() {
inner := errors.New("ichki xatolik")
outer := fmt.Errorf("tashqi qatlam: %w", inner)
unwrapped := errors.Unwrap(outer)
fmt.Println(unwrapped)
}
Natija:
ichki xatolik
errors.Join()Ba'zan bir vaqtning o'zida bir nechta mustaqil xatolik yuz berishi mumkin (masalan, formadagi bir nechta maydon noto'g'ri to'ldirilgan bo'lsa). Ularni bittaga birlashtirish uchun errors.Join() ishlatiladi:
package main
import (
"errors"
"fmt"
)
func main() {
err1 := errors.New("birinchi xato")
err2 := errors.New("ikkinchi xato")
joined := errors.Join(err1, err2)
fmt.Println(joined)
// Is() birlashtirilgan xatolik ichidan har ikkalasini ham topa oladi
fmt.Println(errors.Is(joined, err1))
fmt.Println(errors.Is(joined, err2))
}
Natija:
birinchi xato
ikkinchi xato
true
true
| Vazifa | Funksiya |
|---|---|
| Xatolikka qo'shimcha kontekst qo'shib qaytarish | fmt.Errorf("...: %w", err) |
| Ma'lum bir xatolik yuz berganini tekshirish | errors.Is(err, MaqsadXato) |
| O'ralgan xatolikdan maxsus ma'lumot olish | errors.As(err, &maqsadTur) |
| Bir qatlamni "ochish" | errors.Unwrap(err) |
| Bir nechta xatolikni birlashtirish | errors.Join(err1, err2, ...) |
[!NOTE] Amaliy qoida: agar funksiyangiz boshqa funksiyadan kelgan xatolikni qaytarayotgan bo'lsa, uni doim
%wbilan o'rab qaytaring (shunchaki qayta yozib chiqarish yoki%vishlatish o'rniga). Bu chaqiruvchi tomonga xatolikning "haqiqiy sababi"gacha yetib borish imkonini beradi.