Xatolarni boshqarish — Go’ning boshqa ko’p tillardan tubdan farq qiladigan jihati. Go’da try/catch yo’q — xato oddiy qiymat sifatida, funksiyaning oxirgi qaytish natijasi qilib, ochiq-oydin qaytariladi.
error — Go’ning o’rnatilgan interfeysi:
type error interface { Error() string }. Har qanday tur, agarError() stringmetodiga ega bo’lsa,errorbo’la oladi. Funksiya xato qaytarganda, chaqiruvchi uni albatta tekshirishi kutiladi.
error qaytarish va tekshirish
Funksiya qiymat bilan birga error ham qaytaradi — muvaffaqiyatli bo’lsa, xato o’rniga nil qaytadi:
package main
import "fmt"
func yosh(qiymat int) error {
if qiymat < 0 {
return fmt.Errorf("noto'g'ri yosh: %d manfiy bo'lishi mumkin emas", qiymat)
}
return nil
}
func main() {
err := yosh(-5)
if err != nil {
fmt.Println("Xato:", err)
}
err2 := yosh(25)
if err2 == nil {
fmt.Println("Xato yo'q")
}
}
Xato: noto'g'ri yosh: -5 manfiy bo'lishi mumkin emas
Xato yo'q
fmt.Errorf — fmt.Sprintf kabi formatlaydi, lekin string o’rniga error qaytaradi. if err != nil — Go kodida eng ko’p uchraydigan qatorlardan biri; deyarli har bir funksiya chaqiruvidan keyin xato shu tarzda tekshiriladi.
O’z xato turingizni yaratish
Oddiy matndan ko’proq ma’lumot (masalan, aniq raqamlar) kerak bo’lsa, Error() string metodiga ega maxsus struct yaratiladi:
package main
import "fmt"
type BalansXatosi struct {
Kerak, Mavjud int
}
func (b *BalansXatosi) Error() string {
return fmt.Sprintf("balans yetarli emas: kerak %d, mavjud %d", b.Kerak, b.Mavjud)
}
func yech(balans, summa int) (int, error) {
if summa > balans {
return 0, &BalansXatosi{Kerak: summa, Mavjud: balans}
}
return balans - summa, nil
}
func main() {
_, err := yech(1000, 5000)
if err != nil {
fmt.Println(err)
}
}
balans yetarli emas: kerak 5000, mavjud 1000
*BalansXatosi — Error() string metodiga ega bo’lgani uchun error interfeysini avtomatik qanoatlantiradi (interfeys darsida ko’rgan yashirin qanoatlantirish). fmt.Println(err) chaqirilganda Go avtomatik err.Error()ni chaqiradi.
Xatoni “o’rash” (wrapping) va errors.Is
Katta dasturlarda xato bir necha qatlam funksiya orqali o’tadi. %w verbi orqali asl xatoni yo’qotmasdan, unga kontekst qo’shish mumkin:
package main
import (
"errors"
"fmt"
)
var ErrTopilmadi = errors.New("topilmadi")
func qidir(id int) error {
if id != 1 {
return fmt.Errorf("id %d qidirishda xato: %w", id, ErrTopilmadi)
}
return nil
}
func main() {
err := qidir(5)
fmt.Println(err)
fmt.Println(errors.Is(err, ErrTopilmadi))
}
id 5 qidirishda xato: topilmadi
true
%w — ErrTopilmadini yangi xato ichiga “o’radi”, xabar esa kengaydi. errors.Is(err, ErrTopilmadi) — tashqi xabar boshqacha bo’lsa ham, ichida aynan ErrTopilmadi “o’ralganini” true deb topa oladi. Bu, ayniqsa, “bu xato aynan shu turdanmi?” degan savolga chuqur qatlamlar ortidan ham to’g’ri javob berish uchun kerak.
Nega panic emas, error
Go’da oddiy, kutilgan xato holatlari (fayl topilmadi, noto’g’ri kiritish) uchun har doim error ishlatiladi — panic esa faqat dasturchi xatosi yoki chindan tiklab bo’lmaydigan holat uchun saqlanadi:
| Yondashuv | Qachon ishlatiladi |
|---|---|
error qaytarish |
kutilgan, oddiy xato holatlari (fayl yo’q, noto’g’ri ma’lumot) |
panic |
dasturchi xatosi, tiklab bo’lmaydigan holat (nil ko’rsatkich, massiv chegarasidan chiqish) |
Keyingi darsda aynan panic va uni recover bilan tutib olishni ko’ramiz.