JSON إلى Go Struct
توليد structs في Go من JSON
إدخال JSON
مخرجات Go
ما هو تحويل JSON إلى Go Struct؟
تحويل JSON إلى Go يحوّل بيانات JSON الخام إلى تعريفات أنواع Go التي تعمل مع حزمة encoding/json في المكتبة القياسية للغة. Go لغة ذات أنواع ثابتة، لذا يحتاج كل حقل JSON إلى حقل struct مقابل بالنوع الصحيح ووسم struct يخبر المُسلسِل بمفتاح JSON الذي يجب ربطه. كتابة هذه التعريفات يدويًا لاستجابات API الكبيرة أو المتداخلة بعمق أمر بطيء وعرضة للأخطاء.
تستخدم حزمة encoding/json، المُعرَّفة في مواصفات Go منذ الإصدار 1.0، الانعكاس لمطابقة مفاتيح JSON بحقول struct المُصدَّرة. المطابقة غير حساسة لحالة الأحرف بشكل افتراضي، لكن وسوم struct الصريحة هي الممارسة المعيارية لأنها تُزيل الغموض وتتيح لك استخدام أسلوب PascalCase في Go بينما يبقى JSON بصيغة camelCase أو snake_case. يُؤتمِت المحوّل هذه العملية: يقرأ JSON الخاص بك، ويستنتج أنواع Go من القيم، ويُخرج تعريفات struct بالوسوم الصحيحة.
يتوافق نظام الأنواع في Go بدقة مع JSON. تصبح السلاسل النصية string، والقيم المنطقية bool، والأعداد الصحيحة int، والأعداد العشرية float64. تصبح كائنات JSON المتداخلة structs مسمّاة منفصلة، وتصبح المصفوفات شرائح (slices). الاستثناء الوحيد هو null: لا يوجد في Go نوع nullable عام، لذا تصبح قيم null عادةً أنواع مؤشرات (*string, *int) أو interface{}. يتعامل المولّد مع كل هذا في أجزاء من الثانية.
لماذا تستخدم محوّل JSON إلى Go؟
تعريف structs في Go من JSON يدويًا يعني عدّ الأقواس وتخمين الأنواع وإعادة كتابة الوسوم في كل مرة تتغير فيها الواجهة البرمجية. يُزيل المحوّل هذا الاحتكاك.
حالات استخدام تحويل JSON إلى Go
جدول تعيين أنواع JSON إلى Go
تتبع حزمة encoding/json قواعد محددة عند تعيين قيم JSON إلى أنواع Go. يوضح الجدول أدناه التعيين الافتراضي والبدائل الشائعة. عمود "الافتراضي" هو ما تنتجه معظم المولّدات. يوضح عمود "البديل" الأنواع التي قد تختارها بناءً على متطلباتك، كـint64 للمعرّفات الكبيرة أو أنواع المؤشرات للحقول القابلة للإلغاء.
| نوع JSON | مثال | الافتراضي | البديل |
|---|---|---|---|
| string | "hello" | string | string |
| number (integer) | 42 | int | int64 |
| number (float) | 3.14 | float64 | float64 |
| boolean | true | bool | bool |
| null | null | interface{} | *string / *int |
| object | {"k": "v"} | struct | struct |
| array of strings | ["a", "b"] | []string | []string |
| array of objects | [{"id": 1}] | []Item | []Item |
| mixed array | [1, "a"] | []interface{} | []interface{} |
مرجع وسوم struct في Go لـ JSON
تتحكم وسوم struct في كيفية تسلسل وإلغاء تسلسل الحقول بواسطة encoding/json. وسم json هو الأكثر استخدامًا إلى حد بعيد، لكن يمكنك دمجه مع وسوم أخرى (db وyaml وxml) على الحقل ذاته. صياغة الوسم عبارة عن سلسلة محاطة بعلامات backtick بعد نوع الحقل. فيما يلي خيارات وسم json التي تدعمها encoding/json.
| الوسم | السلوك | حالة الاستخدام |
|---|---|---|
| json:"name" | Maps struct field to JSON key "name" | Always generated |
| json:"name,omitempty" | Omits field from output if zero value | Optional fields |
| json:"-" | Field is never serialized or deserialized | Internal fields |
| json:"name,string" | Encodes int/bool as JSON string | String-encoded numbers |
json.Unmarshal مقابل json.NewDecoder
توفر Go طريقتين لفكّ ترميز JSON: json.Unmarshal للشرائح byte وjson.NewDecoder لتدفقات io.Reader. كلتاهما تستخدمان قواعد وسوم struct ذاتها، لكنهما تختلفان في متى يُستخدم كل منهما.
أمثلة برمجية
تُوضح هذه الأمثلة كيفية استخدام structs في Go المولَّدة من JSON في برامج فعلية، إضافةً إلى كيفية توليدها من لغات أخرى. تستخدم أمثلة Go حزمة encoding/json من المكتبة القياسية.
package main
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
IsActive bool `json:"is_active"`
Tags []string `json:"tags"`
}
func main() {
data := []byte(`{"id":1,"name":"Alice","email":"alice@example.com","is_active":true,"tags":["admin","editor"]}`)
var user User
if err := json.Unmarshal(data, &user); err != nil {
panic(err)
}
fmt.Println(user.Name) // → Alice
fmt.Println(user.Tags) // → [admin editor]
}// JSON response from API — this is the shape you'd convert to Go:
const res = await fetch("https://api.example.com/users/1");
const user = await res.json();
// user → { "id": 1, "name": "Alice", "email": "alice@example.com" }
// Equivalent Go struct:
// type User struct {
// ID int `json:"id"`
// Name string `json:"name"`
// Email string `json:"email"`
// }import json
def json_to_go(data: dict, name: str = "Root") -> str:
lines = [f"type {name} struct {{"]
type_map = {str: "string", int: "int", float: "float64", bool: "bool"}
for key, value in data.items():
go_type = type_map.get(type(value), "interface{}")
field = key.title().replace("_", "") # snake_case → PascalCase
lines.append(f'\t{field} {go_type} `json:"{key}"`')
lines.append("}")
return "\n".join(lines)
data = json.loads('{"user_name": "Alice", "age": 30, "verified": true}')
print(json_to_go(data))
# type Root struct {
# UserName string `json:"user_name"`
# Age int `json:"age"`
# Verified bool `json:"verified"`
# }package main
import (
"encoding/json"
"fmt"
"strings"
)
type Event struct {
Type string `json:"type"`
Payload string `json:"payload"`
}
func main() {
stream := strings.NewReader(`{"type":"click","payload":"btn-1"}
{"type":"scroll","payload":"page-2"}`)
dec := json.NewDecoder(stream)
for dec.More() {
var ev Event
if err := dec.Decode(&ev); err != nil {
break
}
fmt.Printf("%s: %s\n", ev.Type, ev.Payload)
}
// → click: btn-1
// → scroll: page-2
}