معالجة JSON

الدرس 21: معالجة JSON

تشبيه من الحياة

تخيل أنك مترجم. JSON هي "اللغة العالمية" الأكثر استخداماً في العالم. عندما يحتاج برنامج Go للتواصل مع أنظمة أخرى (الواجهة الأمامية، API، قاعدة بيانات)، تحتاج إلى:

تماماً كما يحتاج المترجم لفهم قواعد وأعراف اللغتين، فإن حزمة encoding/json في Go هي أداتك القوية للتعامل مع JSON.


المفاهيم الأساسية

المفهوم الوصف
التسلسل (Marshal) تحويل هياكل بيانات Go إلى شرائح بايت JSON
فك التسلسل (Unmarshal) تحليل شرائح بايت JSON إلى هياكل بيانات Go
وسوم الهيكل (Struct Tag) بيانات وصفية تتحكم في أسماء حقول JSON والسلوك
التدفق (Streaming) استخدام Decoder/Encoder للبيانات الكبيرة أو تدفق الشبكة
التسلسل المخصص تنفيذ واجهات Marshaler/Unmarshaler لمنطق تحويل مخصص

الصياغة الأساسية والاستخدام

1. استيراد الحزمة

GO
import "encoding/json"

2. التسلسل: هيكل ← JSON

GO
// تعريف هيكل
type User struct {
    Name  string
    Age   int
    Email string
}

user := User{Name: "Alice", Age: 28, Email: "alice@example.com"}

// التسلسل
data, err := json.Marshal(user)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(data))
// المخرجات: {"Name":"Alice","Age":28,"Email":"alice@example.com"}
💡 نصيحة: json.Marshal تعيد []byte، تحتاج تحويل string() لطباعة JSON مقروء.

3. فك التسلسل: JSON ← هيكل

GO
jsonStr := `{"Name":"Bob","Age":32,"Email":"bob@example.com"}`

var user User
err := json.Unmarshal([]byte(jsonStr), &user)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("الاسم: %s, العمر: %d\n", user.Name, user.Age)
// المخرجات: الاسم: Bob, العمر: 32
💡 نصيحة: المعامل الثاني لـ Unmarshal يجب أن يكون مؤشراً، وإلا لن تؤثر التغييرات.

4. وسوم الهيكل

GO
type Product struct {
    ID    int     `json:"id"`           // تحديد اسم حقل JSON
    Name  string  `json:"name"`         // التسمية بحروف صغيرة أكثر توافقاً مع JSON
    Price float64 `json:"price"`
    Desc  string  `json:"description,omitempty"` // حذف عند الفراغ
    internal string `json:"-"`          // تجاهل هذا الحقل تماماً
}
💡 نصيحة:

  • omitempty: عندما يكون الحقل قيمة صفرية، سيُحذف من مخرجات JSON
  • -: هذا الحقل لن يظهر أبداً في JSON
  • أسماء الوسوم لها أولوية على أسماء الحقول

5. خرائط الأنواع الشائعة

نوع Go نوع JSON
string string
int, float64 number
bool boolean
nil null
[]T array
map[string]T object
struct object

أمثلة

مثال: تسلسل وفك تسلسل JSON أساسي (الصعوبة ⭐)

GO
package main

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

// هيكل Book
type Book struct {
    Title    string   `json:"title"`
    Author   string   `json:"author"`
    Pages    int      `json:"pages"`
    Tags     []string `json:"tags"`
    InStock  bool     `json:"in_stock"`
}

func main() {
    // === التسلسل ===
    book := Book{
        Title:   "Go in Action",
        Author:  "John Smith",
        Pages:   350,
        Tags:    []string{"Programming", "Go", "Backend"},
        InStock: true,
    }

    // طباعة منسقة (مع مسافات بادئة)
    jsonData, err := json.MarshalIndent(book, "", "  ")
    if err != nil {
        log.Fatal("فشل التسلسل:", err)
    }
    fmt.Println("=== نتيجة التسلسل ===")
    fmt.Println(string(jsonData))

    // === فك التسلسل ===
    jsonStr := `{
        "title": "Mastering Go",
        "author": "Jane Doe",
        "pages": 480,
        "tags": ["Go", "Advanced", "Concurrency"],
        "in_stock": false
    }`

    var newBook Book
    err = json.Unmarshal([]byte(jsonStr), &newBook)
    if err != nil {
        log.Fatal("فشل فك التسلسل:", err)
    }
    fmt.Println("\n=== نتيجة فك التسلسل ===")
    fmt.Printf("العنوان: %s\n", newBook.Title)
    fmt.Printf("المؤلف: %s\n", newBook.Author)
    fmt.Printf("العلامات: %v\n", newBook.Tags)
    fmt.Printf("متوفر: %v\n", newBook.InStock)
}
▶ جرّب الكود

المخرجات:

TEXT
=== نتيجة التسلسل ===
{
  "title": "Go in Action",
  "author": "John Smith",
  "pages": 350,
  "tags": [
    "Programming",
    "Go",
    "Backend"
  ],
  "in_stock": true
}

=== نتيجة فك التسلسل ===
العنوان: Mastering Go
المؤلف: Jane Doe
العلامات: [Go Advanced Concurrency]
متوفر: false

مثال: JSON المتداخل والتعامل مع Map (الصعوبة ⭐⭐)

GO
package main

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

// هيكل العنوان
type Address struct {
    City    string `json:"city"`
    Street  string `json:"street"`
    ZipCode string `json:"zip_code"`
}

// معلومات الاتصال
type Contact struct {
    Phone string `json:"phone"`
    Email string `json:"email"`
}

// هيكل الموظف (مع تداخل)
type Employee struct {
    Name      string            `json:"name"`
    Age       int               `json:"age"`
    Address   Address           `json:"address"`     // هيكل متداخل
    Contact   Contact           `json:"contact"`     // هيكل متداخل
    Skills    []string          `json:"skills"`      // شريحة
    Metadata  map[string]string `json:"metadata"`    // حقول ديناميكية
}

func main() {
    // بناء بيانات متداخلة
    emp := Employee{
        Name: "Alice",
        Age:  35,
        Address: Address{
            City:    "Beijing",
            Street:  "88 Jianguo Road, Chaoyang District",
            ZipCode: "100022",
        },
        Contact: Contact{
            Phone: "13800138000",
            Email: "alice@example.com",
        },
        Skills: []string{"Go", "Python", "Docker"},
        Metadata: map[string]string{
            "department": "Engineering",
            "level":      "P7",
            "joined":     "2020-03-15",
        },
    }

    // التسلسل
    data, err := json.MarshalIndent(emp, "", "  ")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("=== تسلسل JSON متداخل ===")
    fmt.Println(string(data))

    // التعامل مع JSON ديناميكي (باستخدام map)
    dynamicJSON := `{
        "event": "user_login",
        "timestamp": 1700000000,
        "data": {
            "user_id": 12345,
            "ip": "192.168.1.100",
            "browser": "Chrome"
        },
        "tags": ["web", "auth"]
    }`

    var result map[string]interface{}
    err = json.Unmarshal([]byte(dynamicJSON), &result)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("\n=== تحليل JSON ديناميكي ===")
    fmt.Printf("الحدث: %s\n", result["event"])
    fmt.Printf("الوقت: %.0f\n", result["timestamp"])

    // الوصول إلى الخريطة المتداخلة
    if data, ok := result["data"].(map[string]interface{}); ok {
        fmt.Printf("معرف المستخدم: %.0f\n", data["user_id"])
        fmt.Printf("عنوان IP: %s\n", data["ip"])
    }

    // الوصول إلى المصفوفة
    if tags, ok := result["tags"].([]interface{}); ok {
        fmt.Print("العلامات: ")
        for _, tag := range tags {
            fmt.Printf("%s ", tag)
        }
        fmt.Println()
    }
}
▶ جرّب الكود

المخرجات:

TEXT
=== تسلسل JSON متداخل ===
{
  "name": "Alice",
  "age": 35,
  "address": {
    "city": "Beijing",
    "street": "88 Jianguo Road, Chaoyang District",
    "zip_code": "100022"
  },
  "contact": {
    "phone": "13800138000",
    "email": "alice@example.com"
  },
  "skills": [
    "Go",
    "Python",
    "Docker"
  ],
  "metadata": {
    "department": "Engineering",
    "joined": "2020-03-15",
    "level": "P7"
  }
}

=== تحليل JSON ديناميكي ===
الحدث: user_login
الوقت: 1700000000
معرف المستخدم: 12345
عنوان IP: 192.168.1.100
العلامات: web auth

مثال: تسلسل مخصص وتدفق (الصعوبة ⭐⭐⭐)

GO
package main

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

// CustomTime نوع وقت مخصص
type CustomTime struct {
    time.Time
}

// تنفيذ واجهة json.Marshaler
func (ct CustomTime) MarshalJSON() ([]byte, error) {
    // صيغة المخرجات: 2006-01-02 15:04:05
    formatted := ct.Format("2006-01-02 15:04:05")
    return json.Marshal(formatted)
}

// تنفيذ واجهة json.Unmarshaler
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    // دعم تحليل صيغ متعددة
    formats := []string{
        "2006-01-02 15:04:05",
        "2006-01-02T15:04:05",
        "2006/01/02",
    }
    for _, format := range formats {
        t, err := time.Parse(format, s)
        if err == nil {
            ct.Time = t
            return nil
        }
    }
    return fmt.Errorf("غير قادر على تحليل الوقت: %s", s)
}

// Status نوع تعداد مخصص
type Status int

const (
    StatusActive   Status = iota // 0
    StatusInactive               // 1
    StatusBanned                 // 2
)

// خريطة Status إلى نص
var statusNames = map[Status]string{
    StatusActive:   "active",
    StatusInactive: "inactive",
    StatusBanned:   "banned",
}

// خريطة نص إلى Status
var statusValues = map[string]Status{
    "active":   StatusActive,
    "inactive": StatusInactive,
    "banned":   StatusBanned,
}

// MarshalJSON تسلسل مخصص
func (s Status) MarshalJSON() ([]byte, error) {
    name, ok := statusNames[s]
    if !ok {
        return json.Marshal("unknown")
    }
    return json.Marshal(name)
}

// UnmarshalJSON فك تسلسل مخصص
func (s *Status) UnmarshalJSON(data []byte) error {
    var name string
    if err := json.Unmarshal(data, &name); err != nil {
        return err
    }
    val, ok := statusValues[name]
    if !ok {
        return fmt.Errorf("حالة غير معروفة: %s", name)
    }
    *s = val
    return nil
}

// EventLog إدخال سجل الأحداث
type EventLog struct {
    Event     string     `json:"event"`
    Timestamp CustomTime `json:"timestamp"`
    Status    Status     `json:"status"`
    Details   string     `json:"details,omitempty"`
}

func main() {
    // === عرض التسلسل المخصص ===
    logEntry := EventLog{
        Event:     "user_register",
        Timestamp: CustomTime{time.Date(2024, 1, 15, 14, 30, 0, 0, time.Local)},
        Status:    StatusActive,
        Details:   "تم تسجيل مستخدم جديد بنجاح",
    }

    data, _ := json.MarshalIndent(logEntry, "", "  ")
    fmt.Println("=== تسلسل مخصص ===")
    fmt.Println(string(data))

    // === عرض فك التسلسل المخصص ===
    jsonStr := `{
        "event": "user_login",
        "timestamp": "2024/01/15",
        "status": "inactive"
    }`

    var entry EventLog
    err := json.Unmarshal([]byte(jsonStr), &entry)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("\nنتيجة التحليل: الحدث=%s, الوقت=%s, الحالة=%d\n",
        entry.Event,
        entry.Timestamp.Format("2006-01-02 15:04:05"),
        entry.Status,
    )

    // === عرض التدفق ===
    fmt.Println("\n=== Decoder بالتدفق ===")
    // محاكاة تدفق JSON مستلم من الشبكة
    jsonStream := `[
        {"name": "Alice", "score": 95},
        {"name": "Bob", "score": 87},
        {"name": "Charlie", "score": 92}
    ]`

    decoder := json.NewDecoder(strings.NewReader(jsonStream))

    // قراءة رمز البداية
    token, err := decoder.Token()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("رمز البداية: %v\n", token)

    // قراءة عناصر المصفوفة واحداً تلو الآخر
    type Student struct {
        Name  string `json:"name"`
        Score int    `json:"score"`
    }

    var students []Student
    for decoder.More() {
        var s Student
        if err := decoder.Decode(&s); err != nil {
            log.Fatal(err)
        }
        students = append(students, s)
    }

    for _, s := range students {
        fmt.Printf("الطالب: %s, الدرجة: %d\n", s.Name, s.Score)
    }

    // === عرض Encoder بالتدفق ===
    fmt.Println("\n=== Encoder بالتدفق ===")
    var buf strings.Builder
    encoder := json.NewEncoder(&buf)
    encoder.SetIndent("", "  ")

    // تشفير كائنات فردية
    for _, s := range students {
        if err := encoder.Encode(s); err != nil {
            log.Fatal(err)
        }
    }
    fmt.Println(buf.String())
}
▶ جرّب الكود

المخرجات:

TEXT
=== تسلسل مخصص ===
{
  "event": "user_register",
  "timestamp": "2024-01-15 14:30:00",
  "status": "active",
  "details": "تم تسجيل مستخدم جديد بنجاح"
}

نتيجة التحليل: الحدث=user_login, الوقت=2024-01-15 00:00:00, الحالة=1

=== Decoder بالتدفق ===
رمز البداية: [
الطالب: Alice, الدرجة: 95
الطالب: Bob, الدرجة: 87
الطالب: Charlie, الدرجة: 92

=== Encoder بالتدفق ===
{
  "name": "Alice",
  "score": 95
}
{
  "name": "Bob",
  "score": 87
}
{
  "name": "Charlie",
  "score": 92
}

سيناريوهات التطبيق

السيناريو 1: غلاف استجابة API

GO
package main

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

// APIResponse هيكل استجابة API موحد
type APIResponse struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
    Error   string      `json:"error,omitempty"`
}

// SuccessResponse استجابة نجاح
func SuccessResponse(w http.ResponseWriter, data interface{}) {
    resp := APIResponse{
        Code:    200,
        Message: "success",
        Data:    data,
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(resp)
}

// ErrorResponse استجابة خطأ
func ErrorResponse(w http.ResponseWriter, statusCode int, errMsg string) {
    resp := APIResponse{
        Code:    statusCode,
        Message: "error",
        Error:   errMsg,
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(statusCode)
    json.NewEncoder(w).Encode(resp)
}

// UserHandler يعالج طلبات المستخدم
func UserHandler(w http.ResponseWriter, r *http.Request) {
    // بيانات مستخدم محاكاة
    users := []map[string]interface{}{
        {"id": 1, "name": "Alice", "role": "admin"},
        {"id": 2, "name": "Bob", "role": "user"},
        {"id": 3, "name": "Charlie", "role": "user"},
    }

    SuccessResponse(w, users)
}

func main() {
    // محاكاة استجابة API
    fmt.Println("=== محاكاة استجابة API ===")

    // استجابة نجاح
    successResp := APIResponse{
        Code:    200,
        Message: "success",
        Data: map[string]interface{}{
            "id":   1,
            "name": "Alice",
        },
    }
    data, _ := json.MarshalIndent(successResp, "", "  ")
    fmt.Println("استجابة النجاح:")
    fmt.Println(string(data))

    // استجابة خطأ
    errorResp := APIResponse{
        Code:    404,
        Message: "error",
        Error:   "المستخدم غير موجود",
    }
    data, _ = json.MarshalIndent(errorResp, "", "  ")
    fmt.Println("\nاستجابة الخطأ:")
    fmt.Println(string(data))

    _ = log.Fatal // تجنب تحذير غير مستخدم
}

المخرجات:

TEXT
=== محاكاة استجابة API ===
استجابة النجاح:
{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "name": "Alice"
  }
}

استجابة الخطأ:
{
  "code": 404,
  "message": "error",
  "error": "المستخدم غير موجود"
}

السيناريو 2: قراءة والتحقق من ملف التكوين

GO
package main

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

// DatabaseConfig تكوين قاعدة البيانات
type DatabaseConfig struct {
    Host     string `json:"host"`
    Port     int    `json:"port"`
    Username string `json:"username"`
    Password string `json:"password"`
    DBName   string `json:"dbname"`
}

// ServerConfig تكوين الخادم
type ServerConfig struct {
    Host         string   `json:"host"`
    Port         int      `json:"port"`
    ReadTimeout  int      `json:"read_timeout"`
    WriteTimeout int      `json:"write_timeout"`
    AllowOrigins []string `json:"allow_origins"`
}

// AppConfig تكوين التطبيق
type AppConfig struct {
    AppName  string         `json:"app_name"`
    Debug    bool           `json:"debug"`
    Server   ServerConfig   `json:"server"`
    Database DatabaseConfig `json:"database"`
}

// Validate يتحقق من صحة التكوين
func (c *AppConfig) Validate() error {
    if c.AppName == "" {
        return fmt.Errorf("app_name لا يمكن أن يكون فارغاً")
    }
    if c.Server.Port <= 0 || c.Server.Port > 65535 {
        return fmt.Errorf("server.port يجب أن يكون بين 1-65535")
    }
    if c.Database.Host == "" {
        return fmt.Errorf("database.host لا يمكن أن يكون فارغاً")
    }
    return nil
}

func main() {
    // محاكاة محتوى ملف التكوين
    configJSON := `{
        "app_name": "GoWebApp",
        "debug": true,
        "server": {
            "host": "0.0.0.0",
            "port": 8080,
            "read_timeout": 30,
            "write_timeout": 30,
            "allow_origins": ["http://localhost:3000", "https://example.com"]
        },
        "database": {
            "host": "localhost",
            "port": 3306,
            "username": "root",
            "password": "secret123",
            "dbname": "myapp"
        }
    }`

    // تحليل التكوين
    var config AppConfig
    err := json.Unmarshal([]byte(configJSON), &config)
    if err != nil {
        log.Fatalf("فشل تحليل التكوين: %v", err)
    }

    // التحقق من التكوين
    if err := config.Validate(); err != nil {
        log.Fatalf("فشل التحقق من التكوين: %v", err)
    }

    // طباعة معلومات التكوين
    fmt.Printf("اسم التطبيق: %s\n", config.AppName)
    fmt.Printf("وضع التصحيح: %v\n", config.Debug)
    fmt.Printf("عنوان الخادم: %s:%d\n", config.Server.Host, config.Server.Port)
    fmt.Printf("اتصال قاعدة البيانات: %s:%d/%s\n",
        config.Database.Host,
        config.Database.Port,
        config.Database.DBName,
    )
    fmt.Printf("المصادر المسموحة: %v\n", config.Server.AllowOrigins)

    // كتابة مثال (حفظ التكوين المعدّل)
    config.Debug = false
    config.Server.Port = 9090

    output, err := json.MarshalIndent(config, "", "  ")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("\n=== التكوين المعدّل ===")
    fmt.Println(string(output))

    // في مشروع حقيقي، ستكتب في ملف:
    // os.WriteFile("config.json", output, 0644)
    _ = os.WriteFile // تجنب تحذير غير مستخدم
}

المخرجات:

TEXT
اسم التطبيق: GoWebApp
وضع التصحيح: true
عنوان الخادم: 0.0.0.0:8080
اتصال قاعدة البيانات: localhost:3306/myapp
المصادر المسموحة: [http://localhost:3000 https://example.com]

=== التكوين المعدّل ===
{
  "app_name": "GoWebApp",
  "debug": false,
  "server": {
    "host": "0.0.0.0",
    "port": 9090,
    "read_timeout": 30,
    "write_timeout": 30,
    "allow_origins": [
      "http://localhost:3000",
      "https://example.com"
    ]
  },
  "database": {
    "host": "localhost",
    "port": 3306,
    "username": "root",
    "password": "secret123",
    "dbname": "myapp"
  }
}

❓ أسئلة شائعة

س1: لماذا أسماء حقول JSON بأحرف كبيرة؟

السبب: Go يصدر فقط الحقول التي يبدأ حرفها الأول بأحرف كبيرة، و json.Marshal يستخدم اسم الحقل كمفتاح JSON افتراضياً.

الحل: استخدم وسوم الهيكل لتحديد أسماء بأحرف صغيرة:

GO
type User struct {
    Name  string `json:"name"`   // "name" في JSON
    Age   int    `json:"age"`    // "age" في JSON
    Email string `json:"email"`  // "email" في JSON
}

س2: كيف أتجاهل الحقول ذات القيم الفارغة؟

استخدم الوسم omitempty:

GO
type Request struct {
    Name  string `json:"name"`
    Email string `json:"email,omitempty"` // حذف عند نص فارغ
    Age   int    `json:"age,omitempty"`   // حذف عند 0
    Items []string `json:"items,omitempty"` // حذف عند nil أو شريحة فارغة
}

// اختبار
req := Request{Name: "Alice"}
data, _ := json.Marshal(req)
fmt.Println(string(data))
// المخرجات: {"name":"alice"} — email, age, items محذوفة جميعاً

س3: كيف أتعامل مع مشاكل دقة الأرقام في JSON؟

json.Unmarshal في Go تحلل أرقام JSON كـ `float64 افتراضياً، مما يفقد الدقة للأعداد الصحيحة الكبيرة:

GO
// مثال على المشكلة
var result map[string]interface{}
json.Unmarshal([]byte(`{"id": 12345678901234567}`), &result)
fmt.Printf("%.0f\n", result["id"]) // المخرجات: 12345678901234568 (فقدان الدقة!)

// الحل: استخدام json.Number
decoder := json.NewDecoder(strings.NewReader(`{"id": 12345678901234567}`))
decoder.UseNumber()
decoder.Decode(&result)

id, _ := result["id"].(json.Number).Int64()
fmt.Println(id) // المخرجات: 12345678901234567 (صحيح)

س4: كيف أتعامل مع JSON ذو بنية غير معروفة؟

استخدم map[string]interface{} أو json.RawMessage:

GO
// الطريقة 1: استخدام map
var data map[string]interface{}
json.Unmarshal(jsonBytes, &data)

// الطريقة 2: استخدام json.RawMessage للتأخير في التحليل
type Message struct {
    Type    string          `json:"type"`
    Payload json.RawMessage `json:"payload"` // تأخير التحليل
}

// تحديد كيفية تحليل Payload بناءً على حقل Type
switch msg.Type {
case "user":
    var user User
    json.Unmarshal(msg.Payload, &user)
case "order":
    var order Order
    json.Unmarshal(msg.Payload, &order)
}

📖 ملخص

غطى هذا الدرس المحتوى الأساسي لمعالجة JSON في Go:

  1. العمليات الأساسية: json.Marshal للتسلسل و json.Unmarshal لفك التسلسل
  2. وسوم الهيكل: استخدام json:"name" للتحكم في أسماء الحقول، omitempty لحذف القيم الفارغة، - لتجاهل الحقول
  3. التعامل مع التداخل: تداخل الهياكل، map[string]interface{} لـ JSON الديناميكي
  4. التسلسل المخصص: تنفيذ واجهات Marshaler/Unmarshaler
  5. التدفق: json.Decoder و json.Encoder لبيانات التدفق
  6. التطبيقات العملية: أغلفة استجابة API، إدارة ملفات التكوين
💡 نقاط أساسية:

  • تحقق دائماً من معالجة الأخطاء
  • مرر مؤشرات لفك التسلسل
  • استخدم وسوم الهيكل للحفاظ على اصطلاحات تسمية JSON
  • استخدم التدفق لكميات البيانات الكبيرة

📝 تمارين

التمرين 1: تطبيق أساسي

اكتب برنامجاً يحدد هيكل Student (بالاسم والعمر وقائمة درجات)، وينفذ:

  1. إنشاء 3 كائنات طلاب
  2. التسلسل إلى مصفوفة JSON مع طباعة منسقة
  3. فك التسلسل إلى هياكل وطباعة المعلومات

التمرين 2: تطبيق متوسط

نفذ مدير تكوين JSON بسيطاً: 1.حدد هيكل تكوين التطبيق (يحتوي على خادم وقاعدة بيانات وسجلات إلخ) 2. نفذ دالة LoadConfig(filename) لقراءة التكوين من ملف 3. نفذ دالة SaveConfig(filename, config) لحفظ التكوين في ملف 4. نفذ التحقق من التكوين

التمرين 3: تطبيق متقدم

نفذ معالج رسائل JSON-RPC: 1.حدد هياكل الطلبات والاستجابات 2. استخدم json.RawMessage لتأخير التحليل 3. وجه إلى دوال معالجة مختلفة بناءً على اسم طريقة الطلب 4. ادعم معالجة الطلبات بالدفعة

GO
// تلميح: صيغة طلب JSON-RPC
type RPCRequest struct {
    JSONRPC string          `json:"jsonrpc"`
    Method  string          `json:"method"`
    Params  json.RawMessage `json:"params"`
    ID      interface{}     `json:"id"`
}

type RPCResponse struct {
    JSONRPC string      `json:"jsonrpc"`
    Result  interface{} `json:"result,omitempty"`
    Error   *RPCError   `json:"error,omitempty"`
    ID      interface{} `json:"id"`
}

الدرس التالي

بعد إكمال هذا الدرس، يرجى المتابعة إلى الدرس 22: خدمات HTTP، حيث سنتعلم كيفية استخدام Go لبناء خوادم وعملاء HTTP.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%