1. encoding/json मानक पुस्तकालय का अवलोकन

Go भाषा encoding/json पुस्तकालय प्रदान करती है जो JSON डेटा प्रारूप को संभालने के लिए शक्तिशाली है। इस पुस्तकालय के साथ, आप आसानी से Go डेटा प्रकार को JSON प्रारूप में परिवर्तित कर सकते हैं (सिरणीकरण) या JSON डेटा को Go डेटा प्रकारों में परिवर्तित कर सकते हैं (असिरणीकरण)। यह पुस्तकालय कई कार्यों जैसे कोडित, डिकोडित, स्ट्रीमिंग आईओ, और कस्टम JSON विश्लेषण तर्क का समर्थन प्रदान करती है।

इस पुस्तकालय में सबसे महत्वपूर्ण डेटा प्रकार और फ़ंक्शन शामिल हैं:

  • Marshal और MarshalIndent: Go डेटा प्रकारों को JSON स्ट्रिंग में सिरणीकरण के लिए प्रयोग किया जाता है।
  • Unmarshal: JSON स्ट्रिंग को Go डेटा प्रकारों में असिरणीकरण के लिए प्रयोग किया जाता है।
  • Encoder और Decoder: JSON डेटा की स्ट्रीमिंग आईओ के लिए प्रयोग किया जाता है।
  • Valid: दिया गया स्ट्रिंग यदि वैध JSON प्रारूप है तो प्रयोग किया जाता है।

हम आगामी अध्यायों में इन फ़ंक्शनों और प्रकारों के उपयोग को विशेष रूप से सीखेंगे।

2. Go डेटा संरचनाओं को JSON में सिरणीकरण

2.1 json.Marshal का प्रयोग

json.Marshal एक फ़ंक्शन है जो Go डेटा प्रकारों को JSON स्ट्रिंग में सिरणीकरण करता है। यह Go भाषा से डेटा प्रकारों को इनपुट के रूप में लेता है, उन्हें JSON प्रारूप में परिवर्तित करता है, और एक बाइट स्लाइस के साथ संभावित त्रुटियों के साथ लौटाता है।

यहां एक सरल उदाहरण है जो एक Go स्ट्रक्ट को JSON स्ट्रिंग में कैसे परिवर्तित करता है:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    person := Person{"Alice", 30}
    jsonData, err := json.Marshal(person)
    if err != nil {
        log.Fatalf("JSON marshaling failed: %s", err)
    }
    fmt.Println(string(jsonData)) // Output: {"name":"Alice","age":30}
}

स्ट्रक्ट के अलावा, json.Marshal फ़ंक्शन मैप और स्लाइस जैसे अन्य डेटा प्रकारों को सिरणीकरण कर सकता है। नीचे map[string]interface{} और slice का प्रयोग करके उदाहरण है:

// मैप को JSON में परिवर्तित करें
myMap := map[string]interface{}{
    "name": "Bob",
    "age":  25,
}
jsonData, err := json.Marshal(myMap)
// ... त्रुटि हैंडलिंग और आउटपुट छूट दिया गया ...

// स्लाइस को JSON में परिवर्तित करें
mySlice := []string{"Apple", "Banana", "Cherry"}
jsonData, err := json.Marshal(mySlice)
// ... त्रुटि हैंडलिंग और आउटपुट छूट दिया गया ...

2.2 स्ट्रक्ट टैग

Go में, स्ट्रक्ट टैग का उपयोग स्ट्रक्ट फ़ील्ड्स के लिए मेटाडेटा प्रदान करने के लिए किया जाता है, जो JSON सीरियलाइज़ेशन के व्यवहार को नियंत्रित करता है। सबसे सामान्य उपयोग मामले में फ़ील्ड का नाम बदलना, फ़ील्डों को अनदेखा करना, और शर्तबद्ध सीरियलाइज़ेशन शामिल हैं।

उदाहरण के लिए, आप टैग json:"<नाम>" का प्रयोग करके JSON फ़ील्ड का नाम निर्दिष्ट कर सकते हैं:

type Animal struct {
    SpeciesName string `json:"species"`
    Description string `json:"desc,omitempty"`
    Tag         string `json:"-"` // "-" टैग जोड़ने से इस फ़ील्ड का अर्थ है कि इसे सीरियलाइज़ नहीं किया जाएगा
}

ऊपर के उदाहरण में, Tag फ़ील्ड के सामने json:"-" टैग json.Marshal को बताता है कि इस फ़ील्ड को अनदेखा करना है। Description फ़ील्ड के लिए omitempty विकल्प यह दर्शाता है कि यदि फ़ील्ड खाली है (शून्य मान, जैसे रिक्त स्ट्रिंग), तो इसे सिरियलाइज़ किया नहीं जाएगा।

यहां स्ट्रक्ट टैग का प्रयोग करके एक पूरा उदाहरण है:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Animal struct {
    SpeciesName string `json:"species"`
    Description string `json:"desc,omitempty"`
    Tag         string `json:"-"`
}

func main() {
    animal := Animal{
        SpeciesName: "African Elephant",
        Description: "A large mammal with a trunk and tusks.",
        Tag:         "endangered", // इस फ़ील्ड को JSON में सीरियलाइज़ नहीं किया जाएगा
    }
    jsonData, err := json.Marshal(animal)
    if err != nil {
        log.Fatalf("JSON marshaling failed: %s", err)
    }
    fmt.Println(string(jsonData)) // आउटपुट: {"species":"African Elephant","desc":"A large mammal with a trunk and tusks."}
}

इस तरह, आप सुनिश्चित कर सकते हैं कि JSON प्रस्तुति को नियंत्रित करते हुए स्पष्ट डेटा संरचना सुनिश्चित कर सकते हैं, विभिन्न सीरियलाइज़ेशन आवश्यकताओं को लचीलापूर्वक संभाल सकते हैं।

3. JSON को Go डेटा संरचना में असिरणीकरण

3.1 json.Unmarshal का उपयोग

json.Unmarshal फ़ंक्शन हमें JSON स्ट्रिंग को गो डेटा संरचनाओं जैसे कि स्ट्रक्चर, मैप आदि में पार्स करने की अनुमति देता है। json.Unmarshal का उपयोग करने के लिए, हमें पहले एक ऐसा गो डेटा संरचना परिभाषित करनी होती है जो JSON डेटा से मेल खाती हो।

मान लें हमारे पास निम्नलिखित JSON डेटा है:

{
    "name": "Alice",
    "age": 25,
    "emails": ["[email protected]", "[email protected]"]
}

इस डेटा को गो स्ट्रक्चर में पार्स करने के लिए, हमें एक मिलता-जुलता स्ट्रक्चर परिभाषित करना होगा:

type User struct {
    Name   string   `json:"name"`
    Age    int      `json:"age"`
    Emails []string `json:"emails"`
}

अब हम डिसीरियलाइज़ेशन के लिए json.Unmarshal का उपयोग कर सकते हैं:

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonData := `{
        "name": "Alice",
        "age": 25,
        "emails": ["[email protected]", "[email protected]"]
    }`

    var user User
    err := json.Unmarshal([]byte(jsonData), &user)
    if err != nil {
        fmt.Println("JSON का डिसीरियलाइज़ेशन में त्रुटि:", err)
        return
    }

    fmt.Printf("User: %+v\n", user)
}

ऊपर के उदाहरण में, हमने json:"name" जैसे टैग का उपयोग करके json.Unmarshal फ़ंक्शन को JSON फ़ील्ड को स्ट्रक्चर फ़ील्ड के साथ मैप करने के बारे में सूचित किया।

4.2 JSON Arrays

JSON में, arrays एक सामान्य डेटा संरचना हैं। Go में, ये slices के समान होते हैं।

नीचे दिए गए JSON array को ध्यान से देखें:

[
    {"name": "Dave", "age": 34},
    {"name": "Eve", "age": 28}
]

Go में, हम निम्नलिखित struct और slice को निर्धारित करते हैं:

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    jsonData := `[
        {"name": "Dave", "age": 34},
        {"name": "Eve", "age": 28}
    ]`

    var people []Person
    json.Unmarshal([]byte(jsonData), &people)
    
    for _, person := range people {
        fmt.Printf("%+v\n", person)
    }
}

इस तरह, हम JSON array में प्रत्येक तत्व को Go structs के slice में deserialize कर सकते हैं जिससे आगे की प्रक्रिया और पहुंच संभव होती है।

5 त्रुटि संसाधन

JSON डेटा के साथ संबंधित होते समय, चाहे वह serialization (संरचित डेटा को JSON प्रारूप में बदलना) हो या deserialization (JSON को वापस संरचित डेटा में बदलना) हो, त्रुटियाँ हो सकती हैं। आगे, हम सामान्य त्रुटियों और उन्हें संभालने के तरीकों पर चर्चा करेंगे।

5.1 सीरियलाइज़ेशन त्रुटि संसाधन

सीरियलाइज़ेशन त्रुटियाँ सामान्य रूप से एक struct या अन्य डेटा प्रकार को एक JSON स्ट्रिंग में बदलने की प्रक्रिया के दौरान होती हैं। उदाहरण के लिए, अगर किसी struct में गैर कानूनी फील्ड (जैसे एक चैनल प्रकार या फ़ंक्शन) को serialize करने का प्रयास किया जाता है, तो json.Marshal में एक त्रुटि वापस करेगा।

import (
    "encoding/json"
    "fmt"
    "log"
)

type User struct {
    Name string
    Age  int
    // मान लें यहां एक फ़ील्ड है जो सीरियलाइज़ किया नहीं जा सकता
    // Data chan struct{} // चैनल्स को JSON में प्रस्तुत नहीं किया जा सकता
}

func main() {
    u := User{
        Name: "Alice",
        Age:  30,
        // Data: make(chan struct{}),
    }

    bytes, err := json.Marshal(u)
    if err != nil {
        log.Fatalf("JSON serialization failed: %v", err)
    }
    
    fmt.Println(string(bytes))
}

उपरोक्त उदाहरण में, हमने जानबूझकर Data फ़ील्ड को टिप्पणी कर दी है। अगर टिप्पणी हटाई जाती है, तो सीरियलाइज़ेशन विफल होगा, और प्रोग्राम त्रुटि को लॉग करेगा और क्रियान्वयन को समाप्त करेगा। इस प्रकार की त्रुटियों को संभालने में सामान्य रूप से त्रुटियों की जाँच करना और संबंधित त्रुटि संसाधन रणनीतियों (जैसे त्रुटियों को लॉग करना, डिफ़ॉल्ट डेटा वापसी करना, आदि) का अमल करना होता है।

5.2 डीसीरियलाइज़ेशन त्रुटि संसाधन

डीसीरियलाइज़ेशन त्रुटियाँ जब हो सकती हैं, जब JSON स्ट्रिंग को वापस Go struct या अन्य डेटा प्रकार में बदला जाता है। उदाहरण के लिए, अगर JSON स्ट्रिंग प्रारूप गलत हो या लक्ष्य प्रकार के साथ असंगत हो, तो json.Unmarshal एक त्रुटि वापस करेगा।

import (
    "encoding/json"
    "fmt"
    "log"
)

func main() {
    var data = []byte(`{"name":"Alice","age":"unknown"}`) // "age" को एक पूर्णांक होना चाहिए, लेकिन यहां एक स्ट्रिंग प्रदान की गई है
    var u User

    err := json.Unmarshal(data, &u)
    if err != nil {
        log.Fatalf("JSON deserialization failed: %v", err)
    }
    
    fmt.Printf("%+v\n", u)
}

इस कोड उदाहरण में, हमने जानबूझकर age फ़ील्ड के लिए गलत डेटा प्रकार प्रदान किया है (पूर्णांक की बजाय एक स्ट्रिंग), जिससे json.Unmarshal एक त्रुटि फेंकेगा। इसलिए, हमें इस स्थिति का सामान्य तरीके से संभालने की आवश्यकता है। सामान्य अभ्यास है कि हम त्रुटि संदेश को लॉग करें और स्थिति के आधार पर संभावना के हिसाब से एक खाली ऑब्जेक्ट, डिफ़ॉल्ट मान या त्रुटि संदेश वापसी करें।

6 उन्नत सुविधाएँ और प्रदर्शन अनुकूलन

6.1 कस्टम मार्शल और अनमार्शल

गो में, डिफ़ॉल्ट रूप से encoding/json पैकेज JSON को reflection के माध्यम से serialize और deserialize करता है। हालांकि, हम json.Marshaler और json.Unmarshaler इंटरफेस को लागू करके इन प्रक्रियाओं को अनुकूलित कर सकते हैं।

import (
    "encoding/json"
    "fmt"
)

type Color struct {
    Red   uint8
    Green uint8
    Blue  uint8
}

func (c Color) MarshalJSON() ([]byte, error) {
    hex := fmt.Sprintf("\"#%02x%02x%02x\"", c.Red, c.Green, c.Blue)
    return []byte(hex), nil
}

func (c *Color) UnmarshalJSON(data []byte) error {
    _, err := fmt.Sscanf(string(data), "\"#%02x%02x%02x\"", &c.Red, &c.Green, &c.Blue)
    return err
}

func main() {
    c := Color{Red: 255, Green: 99, Blue: 71}
    
    jsonColor, _ := json.Marshal(c)
    fmt.Println(string(jsonColor))

    var newColor Color
    json.Unmarshal(jsonColor, &newColor)
    fmt.Println(newColor)
}

यहां, हमने Color टाइप को परिभाषित किया है और MarshalJSON और UnmarshalJSON मेथड्स को संख्यात्मक रूप में रंगों को हेक्साडेसिमल स्ट्रिंग में और फिर से रंगों को एरजीबी में कन्वर्ट करने के लिए अंमल किया है।

6.2 इनकोडर्स और डीकोडर्स

जब भीड़ JSON डेटा के साथ काम करते हैं, json.Marshal और json.Unmarshal का सीधा उपयोग अधिक मेमोरी उपभोग या अपर्याप्त इनपुट/आउटपुट प्रक्रियाओं की ओर ले जा सकता है। इसलिए, गो में encoding/json पैकेज द्वारा Encoder और Decoder टाइप्स प्रदान किए गए हैं, जो JSON डेटा को स्ट्रीमिंग तरीके से प्रसंस्करण कर सकते हैं।

6.2.1 json.Encoder का उपयोग

json.Encoder सीधे वहाँ JSON डेटा को किसी भी ऑब्जेक्ट में लिख सकता है जो io.Writer इंटरफेस को अनुकरण करता है, जिससे आप JSON डेटा को सीधे फ़ाइल, नेटवर्क कनेक्शन, आदि में एनकोड कर सकते हैं।

import (
    "encoding/json"
    "os"
)

func main() {
    users := []User{
        {Name: "Alice", Age: 30},
        {Name: "Bob", Age: 25},
    }
    
    file, _ := os.Create("users.json")
    defer file.Close()
    
    encoder := json.NewEncoder(file)
    if err := encoder.Encode(users); err != nil {
        log.Fatalf("Encoding error: %v", err)
    }
}

6.2.2 json.Decoder का उपयोग

json.Decoder सीधे वहाँ JSON डेटा को किसी भी ऑब्जेक्ट में डेड कर सकता है जो io.Reader इंटरफेस को अनुकरण करता है, जांचता है और JSON ऑब्ज