Go’da JSON bilan ishlash
JSON matn ko‘rinishidagi ma’lumot almashish formatidir. Go’da encoding/json paketi JSON’ni Go qiymatiga dekodlaydi va Go qiymatini JSON ko‘rinishiga kodlaydi.
JSON va Go turlari
JSON qiymatlari odatda quyidagicha mos keladi:
| JSON | Go’da odatiy tur |
|---|---|
| string | string |
| number | int, float64 yoki boshqa son turi |
| boolean | bool |
| array | slice yoki array |
| object | struct yoki map |
| null | pointer, slice, map yoki interface uchun nil |
Struct orqali dekodlashda faqat eksport qilinadigan, ya’ni katta harf bilan boshlangan fieldlar ishlatiladi.
Struct tag
type User struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
Password string `json:"-"`
Roles []string `json:"roles"`
}
json:"name" JSON kalitini belgilaydi. omitempty qiymat bo‘sh bo‘lsa fieldni kodlangan natijadan chiqaradi. json:"-" fieldni JSON kodlash va dekodlashdan butunlay chetlatadi.
Marshal va Unmarshal
json.Marshal() xotiradagi qiymatni []bytega kodlaydi, json.Unmarshal() esa to‘liq []byteni qiymatga dekodlaydi:
data, err := json.Marshal(User{Name: "Ali", Roles: []string{"editor"}})
if err != nil {
return err
}
var user User
if err := json.Unmarshal(data, &user); err != nil {
return err
}
Unmarshalga qiymatning o‘zi emas, yozish mumkin bo‘lgan pointer uzatiladi. Kichik va to‘liq xotirada mavjud JSON uchun bu funksiyalar qulay.
Encoder va Decoder
json.NewEncoder(w) natijani io.Writerga, json.NewDecoder(r) esa io.Readerdan oqim tarzida ishlaydi:
Fayl, terminal yoki tarmoq ulanishi kabi oqim bilan ishlaganda Encoder va Decoder ortiqcha oraliq []byte yaratmaslikka yordam beradi. Encode natija oxiriga yangi qator ham qo‘shadi.
Qat’iy dekodlash
Konfiguratsiyada noto‘g‘ri yozilgan fieldni jim e’tiborsiz qoldirish xavfli. DisallowUnknownFields() noma’lum fieldni xato qiladi. Bitta JSON qiymatidan keyingi ortiqcha qiymatni ham tekshirish kerak:
func decodeConfig(r io.Reader) (Config, error) {
var cfg Config
dec := json.NewDecoder(r)
dec.DisallowUnknownFields()
if err := dec.Decode(&cfg); err != nil {
return Config{}, fmt.Errorf("JSON o‘qilmadi: %w", err)
}
if err := dec.Decode(&struct{}{}); err != io.EOF {
if err == nil {
return Config{}, errors.New("faqat bitta JSON qiymati kutilgan")
}
return Config{}, fmt.Errorf("ortiqcha JSON qiymati: %w", err)
}
return cfg, nil
}
Bu funksiya uchun encoding/json, errors, fmt va io import qilinadi. Ikkinchi Decode io.EOF qaytarsa, oqimda boshqa qiymat yo‘q.
Xato turlari
Noto‘g‘ri JSON sintaksisi *json.SyntaxError, JSON qiymati Go field turiga mos kelmasligi esa *json.UnmarshalTypeError bo‘lishi mumkin:
var syntaxErr *json.SyntaxError
var typeErr *json.UnmarshalTypeError
switch {
case errors.As(err, &syntaxErr):
fmt.Printf("JSON sintaksisi xato, offset: %d\n", syntaxErr.Offset)
case errors.As(err, &typeErr):
fmt.Printf("%s field uchun tur noto‘g‘ri\n", typeErr.Field)
default:
fmt.Println("JSON o‘qilmadi")
}
Ichki xato diagnostikasini logda saqlash mumkin. Tashqi foydalanuvchiga fayl yo‘li, maxfiy qiymat yoki ichki implementatsiyani oshkor qilmaydigan qisqa xabar qaytaring.
Konfiguratsiya misoli
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
)
type Config struct {
Address string `json:"address"`
Debug bool `json:"debug"`
}
func main() {
input := `{"address":"localhost:8080","debug":true}`
var cfg Config
dec := json.NewDecoder(strings.NewReader(input))
dec.DisallowUnknownFields()
if err := dec.Decode(&cfg); err != nil {
log.Fatal("konfiguratsiya o‘qilmadi: ", err)
}
fmt.Printf("Manzil: %s, debug: %t\n", cfg.Address, cfg.Debug)
}
Bu misol JSON’ni fayl yoki HTTP’ga bog‘lamaydi. strings.Reader matnni io.Reader sifatida beradi, decoder esa uni Config structiga yozadi.
Xulosa
Marshal va Unmarshal tayyor baytlar, Encoder va Decoder esa oqimlar uchun qulay. Struct fieldlari eksport qilinishi kerak. Ishonchli konfiguratsiyada noma’lum field va ortiqcha JSON qiymatlarini rad eting, xato tafsilotlarini esa xavfsiz ko‘rsating.