14-bo‘lim
Xatolar bilan ishlash
error interfeysi, errors.New va fmt.Errorf, xatoni o'rash, errors.Is va errors.As, nishon xatolar hamda o'z xato turlaringiz.
Ushbu bo‘lim mundarijasi
Go da xato - oddiy qiymat. Uni qaytarasiz, tekshirasiz,
uzatasiz. Hech qanday try, catch yoki throw yo'q.
error - bu shunchaki interfeys #
package main
import (
"errors"
"fmt"
)
func bol(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("nolga bo'lish mumkin emas")
}
return a / b, nil
}
func main() {
natija, xato := bol(10, 4)
if xato != nil {
fmt.Println("xato:", xato)
return
}
fmt.Println(natija)
if _, xato := bol(1, 0); xato != nil {
fmt.Println("xato:", xato)
}
}
2.5
xato: nolga bo'lish mumkin emas
error - standart kutubxonadagi interfeys va u bitta metoddan
iborat:
type error interface {
Error() string
}
Ya'ni Error() string metodi bor har qanday tur xato bo'la oladi.
fmt.Errorf bilan tafsilot qo'shish #
package main
import (
"fmt"
"strconv"
)
func yoshniOqi(matn string) (int, error) {
son, xato := strconv.Atoi(matn)
if xato != nil {
return 0, fmt.Errorf("yosh noto'g'ri: %w", xato)
}
if son < 0 || son > 150 {
return 0, fmt.Errorf("yosh chegaradan tashqarida: %d", son)
}
return son, nil
}
func main() {
fmt.Println(yoshniOqi("25"))
fmt.Println(yoshniOqi("salom"))
fmt.Println(yoshniOqi("200"))
}
25 <nil>
0 yosh noto'g'ri: strconv.Atoi: parsing "salom": invalid syntax
0 yosh chegaradan tashqarida: 200
fmt.Errorf - Sprintf kabi, lekin satr emas, xato qaytaradi.
%w shabloni maxsus: u ichkaridagi xatoni o'rab saqlaydi.
Buni quyida ko'ramiz.
Xatoni o'rash #
package main
import (
"errors"
"fmt"
)
var XatoTopilmadi = errors.New("topilmadi")
func bazadanOl(id int) error {
if id > 100 {
return fmt.Errorf("talaba %d: %w", id, XatoTopilmadi)
}
return nil
}
func main() {
xato := bazadanOl(500)
fmt.Println(xato)
fmt.Println(errors.Is(xato, XatoTopilmadi))
fmt.Println(errors.Unwrap(xato) == XatoTopilmadi)
fmt.Println(errors.Is(bazadanOl(5), XatoTopilmadi))
}
talaba 500: topilmadi
true
true
false
Bu Go dagi juda muhim naqsh:
XatoTopilmadi- nishon xato (sentinel). U paket darajasida bir marta e'lon qilinadi.%wbilan o'ralganda, tashqi xato kontekst qo'shadi, lekin ichkarisi saqlanadi.errors.Isbutun zanjir bo'ylab qidiradi.
Bu juda keng tarqalgan xato:
if xato.Error() == "topilmadi" {
Nega yomon: xato matni odamlar uchun yozilgan. Kimdir uni aniqroq qilib o'zgartirsa yoki kontekst qo'shsa, tekshiruv jimgina ishlamay qoladi.
To'g'ri yo'l - errors.Is:
if errors.Is(xato, XatoTopilmadi) {
U o'ralgan xatolar zanjirini ham tekshiradi.
%w va %v farqi #
package main
import (
"errors"
"fmt"
)
var Asosiy = errors.New("asosiy xato")
func main() {
oralgan := fmt.Errorf("kontekst: %w", Asosiy)
oddiy := fmt.Errorf("kontekst: %v", Asosiy)
fmt.Println(oralgan)
fmt.Println(oddiy)
fmt.Println(errors.Is(oralgan, Asosiy))
fmt.Println(errors.Is(oddiy, Asosiy))
}
kontekst: asosiy xato
kontekst: asosiy xato
true
false
Ikkala xato bir xil ko'rinadi, lekin ular boshqacha.
%v xatoni oddiy matnga aylantiradi va bog'lanish uziladi. %w
esa asl xatoni saqlab qoladi.
Qoida: xatoni uzatayotganingizda deyarli har doim %w.
O'z xato turingiz #
package main
import (
"errors"
"fmt"
)
type TekshiruvXatosi struct {
Maydon string
Sabab string
}
func (x *TekshiruvXatosi) Error() string {
return fmt.Sprintf("%s: %s", x.Maydon, x.Sabab)
}
func tekshir(ism string, yosh int) error {
if ism == "" {
return &TekshiruvXatosi{Maydon: "ism", Sabab: "bo'sh"}
}
if yosh < 0 {
return &TekshiruvXatosi{Maydon: "yosh", Sabab: "manfiy"}
}
return nil
}
func main() {
xato := tekshir("", 20)
fmt.Println(xato)
var tx *TekshiruvXatosi
if errors.As(xato, &tx) {
fmt.Println("muammoli maydon:", tx.Maydon)
}
fmt.Println(tekshir("Malika", 20))
}
ism: bo'sh
muammoli maydon: ism
<nil>
errors.As - "zanjirda shu turdagi xato bormi" degan savolga
javob beradi va topilsa, uni ko'rsatilgan o'zgaruvchiga yozadi.
| Funksiya | Savol |
|---|---|
errors.Is | Bu aynan o'sha xatomi |
errors.As | Zanjirda shu turdagi xato bormi |
errors.Unwrap | Bir qavat ichkariga |
errors.Join | Bir nechta xatoni birlashtirish |
errors.As(xato, &tx) dagi & ni tushuntirish kerak.
tx ning o'zi allaqachon *TekshiruvXatosi - ya'ni ko'rsatkich.
errors.As esa topilgan xatoni unga yozishi kerak, shuning
uchun unga o'zgaruvchining manzili - &tx beriladi.
Bu 8-bo'limdagi qoidaning aynan o'zi: funksiya o'zgaruvchini o'zgartirishi uchun uning manzili kerak.
Bir nechta xatoni birlashtirish #
package main
import (
"errors"
"fmt"
)
func hammasiniTekshir(ism, email string, yosh int) error {
var xatolar []error
if ism == "" {
xatolar = append(xatolar, errors.New("ism bo'sh"))
}
if email == "" {
xatolar = append(xatolar, errors.New("email bo'sh"))
}
if yosh < 18 {
xatolar = append(xatolar, errors.New("yosh 18 dan kichik"))
}
return errors.Join(xatolar...)
}
func main() {
xato := hammasiniTekshir("", "", 15)
fmt.Println(xato)
fmt.Println("---")
fmt.Println(hammasiniTekshir("Aziza", "[email protected]", 20))
}
ism bo'sh
email bo'sh
yosh 18 dan kichik
---
<nil>
errors.Join (Go 1.20) bir nechta xatoni bitta qilib
birlashtiradi. Chop etilganda har biri yangi qatorda chiqadi.
Agar hamma argument nil bo'lsa, natija ham nil bo'ladi -
shuning uchun ikkinchi chaqiruv <nil> berdi.
Xatolarni qayerda hal qilish kerak #
package main
import (
"errors"
"fmt"
"strconv"
)
var XatoBuzuqQator = errors.New("qator buzuq")
func qatorniOqi(qator string) (int, error) {
son, xato := strconv.Atoi(qator)
if xato != nil {
return 0, fmt.Errorf("%q: %w", qator, XatoBuzuqQator)
}
return son, nil
}
func hammasiniQosh(qatorlar []string) (int, error) {
jami := 0
for i, q := range qatorlar {
son, xato := qatorniOqi(q)
if xato != nil {
return 0, fmt.Errorf("%d-qator: %w", i+1, xato)
}
jami += son
}
return jami, nil
}
func main() {
fmt.Println(hammasiniQosh([]string{"10", "20", "30"}))
_, xato := hammasiniQosh([]string{"10", "buzuq", "30"})
fmt.Println(xato)
fmt.Println(errors.Is(xato, XatoBuzuqQator))
}
60 <nil>
2-qator: "buzuq": qator buzuq
true
Har bir daraja o'z kontekstini qo'shadi va xatoni yuqoriga uzatadi. Natijada xabar butun yo'lni ko'rsatadi.
Xato faqat eng yuqorida - foydalanuvchiga ko'rsatiladigan joyda hal qilinadi.
Yaxshi xato xabari o'qiganda hamma narsani aytadi:
2-qator: "buzuq": qator buzuq.
Ikki keng tarqalgan xato bor:
- Kontekstsiz uzatish:
return xato. Shunda oxirida faqatinvalid syntaxqoladi va qayerdan kelgani noma'lum. - Takrorlash:
return fmt.Errorf("xato yuz berdi: %w", xato). "Xato yuz berdi" hech qanday yangi ma'lumot bermaydi.
Qoida: har bir daraja o'zi biladigan narsani qo'shsin - qator raqami, fayl nomi, identifikator.
Va yana: xato matnini kichik harf bilan boshlang va oxiriga nuqta qo'ymang. Chunki u boshqa xabar ichiga qo'yilishi mumkin.
Xatoni e'tiborsiz qoldirish #
package main
import (
"fmt"
"strconv"
)
func main() {
son, _ := strconv.Atoi("42")
fmt.Println(son)
buzuq, _ := strconv.Atoi("salom")
fmt.Println(buzuq)
}
42
0
_ bilan xatoni ataylab tashlab yuborish mumkin.
Ikkinchi misolda buzuq 0 bo'lib qoldi va dastur hech narsa
sezmadi. Agar bu haqiqiy hisobda ishlatilsa, natija jimgina
noto'g'ri bo'lardi.
_ ni faqat xato haqiqatan ham mumkin bo'lmagan joyda
ishlating - masalan, o'zingiz yozgan doimiy satrni o'qiyotganda.
Shubha bo'lsa, tekshiring. Go da ortiqcha uch qator yozish - eng arzon himoya.
errors.Newbilan xato qaytaruvchi funksiya yozing.fmt.Errorfbilan kontekst qo'shing.- Nishon xato e'lon qilib,
errors.Isbilan tekshiring. %wva%vfarqini isbotlang.- O'z xato turingizni
Error()metodi bilan yozing. errors.Asbilan xato turidan maydon oling.errors.Joinbilan uch xatoni birlashtiring.- Ikki darajali funksiyada kontekst qo'shib uzating.
- Xatoni matn bo'yicha taqqoslab, nega yomonligini o'ylang.
_bilan xatoni tashlab, oqibatini ko'ring.
Xulosa #
error- bitta metodli interfeys; xato - oddiy qiymat.errors.Newsodda xato,fmt.Errorfesa kontekstli xato yaratadi.%wichkaridagi xatoni saqlaydi,%vesa bog'lanishni uzadi.errors.Isaynan o'sha xatoni,errors.Asesa o'sha turdagi xatoni qidiradi - ikkalasi ham butun zanjir bo'ylab.- Xatoni matn bo'yicha taqqoslamang.
errors.Joinbir nechta xatoni birlashtiradi; hammasinilbo'lsa, natija hamnil.- Har bir daraja o'z kontekstini qo'shib uzatsin; xato eng yuqorida hal qilinadi.
- Xato matni kichik harf bilan boshlanadi va nuqtasiz tugaydi.
Keyingi bo'limda panic va recover ni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.