Mashqlar
Bu bo’lim xatoliklar bilan ishlashni - error qiymatlari, o’z xatolik turlari, o’rash (%w), errors.Is/errors.As, defer va panic/recover ni - mustahkamlash uchun. Har bir masalani avval o’zingiz yozing va ishga tushirib ko’ring, keyingina yechimni oching.
1. Xatolik qaytarish
bolish(a, b int) (int, error) funksiyasini yozing. b == 0 bo’lsa errors.New bilan "nolga bo'lish mumkin emas" xatoligini qaytarsin, aks holda bo’linma va nil. main da ikkala holatni ham tekshiring.
Yechimni ko’rish
package main
import (
"errors"
"fmt"
)
func bolish(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("nolga bo'lish mumkin emas")
}
return a / b, nil
}
func main() {
if _, err := bolish(10, 0); err != nil {
fmt.Println("xatolik:", err)
}
if n, err := bolish(10, 2); err == nil {
fmt.Println("natija:", n)
}
}Natija:
xatolik: nolga bo'lish mumkin emas
natija: 52. O’z xatolik turingiz
NotFoundError degan struct yasang, unda Key string maydoni bo’lsin, va unga Error() string metodini qo’shing - u "topilmadi: <Key>" matnini qaytarsin. Bu turni error sifatida qaytaring va chop eting.
Yechimni ko’rish
package main
import "fmt"
type NotFoundError struct {
Key string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("topilmadi: %s", e.Key)
}
func qidir(key string) error {
return &NotFoundError{Key: key}
}
func main() {
err := qidir("user_42")
fmt.Println(err)
}Natija:
topilmadi: user_423. Sentinel xatolikni %w bilan o’rash
ErrTopilmadi degan sentinel error e’lon qiling. foydalanuvchiOl(id int) funksiyasi uni fmt.Errorf va %w bilan o’rab, kontekst (foydalanuvchi id) qo’shib qaytarsin. main da to’liq xabarni va errors.Unwrap orqali asl xatolikni chop eting.
Yechimni ko’rish
package main
import (
"errors"
"fmt"
)
var ErrTopilmadi = errors.New("element topilmadi")
func foydalanuvchiOl(id int) error {
return fmt.Errorf("foydalanuvchi %d ni olishda: %w", id, ErrTopilmadi)
}
func main() {
err := foydalanuvchiOl(42)
fmt.Println(err)
fmt.Println("asl:", errors.Unwrap(err))
}Natija:
foydalanuvchi 42 ni olishda: element topilmadi
asl: element topilmadi4. errors.Is bilan tekshirish
3-mashqdagi o’ralgan xatolikni oling. Uni bir marta == bilan, bir marta errors.Is bilan ErrTopilmadi ga solishtiring va ikkalasining natijasini chop eting. Nega farq qilishini tushunib oling.
Yechimni ko’rish
package main
import (
"errors"
"fmt"
)
var ErrTopilmadi = errors.New("element topilmadi")
func foydalanuvchiOl(id int) error {
return fmt.Errorf("foydalanuvchi %d: %w", id, ErrTopilmadi)
}
func main() {
err := foydalanuvchiOl(42)
fmt.Println("==: ", err == ErrTopilmadi)
fmt.Println("errors.Is:", errors.Is(err, ErrTopilmadi))
}Natija:
==: false
errors.Is: true5. errors.As bilan turni ajratib olish
2-mashqdagi NotFoundError ni fmt.Errorf("...: %w", ...) bilan o’rab qaytaring. main da errors.As yordamida o’ram ichidan *NotFoundError ni ajratib oling va uning Key maydonini chop eting.
Yechimni ko’rish
package main
import (
"errors"
"fmt"
)
type NotFoundError struct {
Key string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("topilmadi: %s", e.Key)
}
func qidir() error {
asl := &NotFoundError{Key: "user_42"}
return fmt.Errorf("bazada qidirishda: %w", asl)
}
func main() {
var nf *NotFoundError
if errors.As(qidir(), &nf) {
fmt.Println("yo'q kalit:", nf.Key)
}
}Natija:
yo'q kalit: user_426. defer ning LIFO tartibi
main ichida uchta defer fmt.Println(...) yozing - 1, 2, 3 sonlarini. Ular qaysi tartibda chop etilishini oldindan ayting, keyin ishga tushirib tekshiring.
Yechimni ko’rish
package main
import "fmt"
func main() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("main tanasi")
}defer LIFO (oxirgisi birinchi) tartibida ishlaydi, shuning uchun 3, 2, 1 chiqadi:
main tanasi
3
2
17. panic ni error ga aylantirish
xavfsizBolish(a, b int) (natija int, err error) funksiyasini yozing. U a / b ni hisoblasin, lekin b == 0 bo’lganda hosil bo’ladigan panic’ni defer + recover bilan ushlab, uni oddiy error ga aylantirib qaytarsin. Dastur crash bo’lmasligi kerak.
Yechimni ko’rish
package main
import "fmt"
func xavfsizBolish(a, b int) (natija int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("hisoblashda panic: %v", r)
}
}()
natija = a / b // b == 0 bo'lsa panic
return natija, nil
}
func main() {
n, err := xavfsizBolish(10, 0)
fmt.Println("natija:", n, "| err:", err)
}Natija:
natija: 0 | err: hisoblashda panic: runtime error: integer divide by zeroShu bilan xatoliklar bo’limi mashqlari tugadi. Endi Go da xatoliklarni qiymat sifatida tekshirishdan tortib panic/recover gacha - hammasini amalda sinab ko’rdingiz.