Menu
flag Ar iconالعربيةdown icon

JSON في Golang: Marshal وUnmarshal ووسوم البنى

كيف ترمّز JSON وتفكّ ترميزه في Go بـ encoding/json: Marshal وUnmarshal، وسوم البنى مثل omitempty وomitzero، الطباعة المنسّقة، فكّ الترميز إلى map[string]any، رفض الحقول المجهولة، والتدفّق بـ Decoder.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

Marshal وUnmarshal

تحوّل json.Marshal قيمة Go إلى بايتات JSON. وتملأ json.Unmarshal قيمة Go من بايتات JSON. وتختار وسوم البنى أسماء حقول JSON.

يغيب Email عن المخرجات الأولى بسبب omitempty ونص فارغ. تحتاج Unmarshal مؤشرًا (&back)؛ وتمرير القيمة نفسها يعيد InvalidUnmarshalError.

وسوم البنى

صيغة الوسم هي json:"name,option,option".

الوسمالأثر
json:"user_id"استخدام user_id مفتاحًا
json:"email,omitempty"الإسقاط عند false أو 0 أو "" أو nil أو شريحة أو خريطة فارغة
json:",omitzero" (Go 1.24)الإسقاط عندما تكون القيمة صفرية، أو يعيد IsZero() القيمة true
json:"-"عدم ترميز هذا الحقل أو فكّ ترميزه أبدًا
json:"-,"استخدام المفتاح الحرفي -
json:"count,string"ترميز رقم أو قيمة منطقية كنص JSON ("42")
بلا وسمالمفتاح هو اسم الحقل في Go، UserID

لا تغادر كلمة المرور البنية أبدًا، ويوضع الرصيد بين علامتي اقتباس، ويختفي deleted_at بينما يطبع created_at الوقت الصفري 0001-01-01T00:00:00Z. هذا الفرق هو سبب إضافة omitzero: لم يعمل omitempty مع البنى قط، وهي مفاجأة قديمة مع time.Time. في Go 1.23 وما قبله استخدم *time.Time مع omitempty للحصول على الأثر نفسه.

تنتج MarshalIndent(v, prefix, indent) مخرجات مقروءة. استخدمها لملفات الإعدادات وتتبّع الأخطاء؛ أما الواجهات البرمجية فترسل JSON مضغوطًا عادة.

الحقول المُصدَّرة فقط

تستخدم encoding/json الانعكاس (reflection) ولا ترى إلا الحقول المُصدَّرة. هذا أشيع خطأ في JSON في Go:

type point struct {
	x, y int // lowercase: json.Marshal(point{1, 2}) gives {}
}

لا خطأ ولا تحذير، فقط {} عند الإخراج وحقول باقية على الصفر عند الإدخال. اجعل الحروف الأولى كبيرة وأضف وسومًا للمفاتيح ذات الحروف الصغيرة.

كيف يطابق فكّ الترميز الحقول

عند فكّ الترميز إلى بنية:

  • تُطابق المفاتيح مع اسم الوسم، أو مع اسم الحقل، دون تمييز حالة الأحرف. يملأ {"NAME": "x"} حقلًا موسومًا بـ json:"name".
  • المفاتيح التي لا حقل مطابقًا لها تُتجاهل بصمت.
  • الحقول التي لا مفتاح مطابقًا لها تحتفظ بقيمتها الحالية. لا تعيد Unmarshal ضبطها، ففكّ الترميز إلى بنية فيها بيانات يدمج فيها.
  • عدم تطابق النوع (نص حيث في البنية int) يعيد *json.UnmarshalTypeError، لكن الحقول الأخرى تُملأ مع ذلك.

لرفض المفاتيح غير المتوقّعة، مثلًا في واجهة برمجية صارمة أو ملف إعدادات فيه أخطاء كتابة، استخدم Decoder مع DisallowUnknownFields:

بنية مجهولة: map[string]any

عندما لا تعرف الشكل مسبقًا، فكّ الترميز إلى map[string]any أو any. التحويل ثابت:

JSONGo
كائنmap[string]any
مصفوفة[]any
نصstring
رقمfloat64
true / falsebool
nullnil

يظهر فخّان في المخرجات. كل رقم float64، فتفشل m["stock"].(int). والأعداد الصحيحة الأكبر من 2^53 تفقد دقتها كـ float64: المعرّف 9007199254740993 يعود بالشكل ...992. يتجنّب UseNumber الأمرين.

إذا كنت تعرف جزءًا من البنية، ففكّ ترميز ذلك الجزء إلى بنية واستخدم json.RawMessage للباقي. يحمل البايتات الخام لحقل لتفكّ ترميزه لاحقًا، بعد أن تعرف نوعه.

الشرائح والخرائط والمؤشرات وnil

قيمة GoJSON
شريحة nil (var s []int)null
شريحة فارغة ([]int{})[]
خريطة nilnull
مؤشر nilnull
[]byteنص بترميز base64
map[string]Tكائن، بمفاتيح مرتّبة
map[int]Tكائن بمفاتيح صحيحة مكتوبة كنصوص

الفرق بين الشريحة nil والشريحة الفارغة مهم لعملاء الواجهات البرمجية الذين يتوقّعون مصفوفة. هيّئ بـ []T{} أو make([]T, 0) عندما يجب أن يكون الحقل [].

استخدم حقل مؤشر (*int أو *bool) عندما تحتاج التمييز بين "غائب" و"صفر" في المدخلات. بعد فكّ الترميز يعني المؤشر nil أن المفتاح مفقود أو null؛ والمؤشر إلى 0 يعني أن العميل أرسل 0.

التدفّقات: Encoder وDecoder

تعمل json.Marshal وUnmarshal على شرائح بايتات كاملة. أما لـ io.Reader أو io.Writer (جسم HTTP، أو ملف، أو stdin) فاستخدم json.NewDecoder وjson.NewEncoder. ويستطيع الـ Decoder أيضًا قراءة سلسلة من قيم JSON واحدة تلو الأخرى:

يكتب Encoder.Encode سطرًا جديدًا بعد كل قيمة. افتراضيًا يهرّب كل من Marshal وEncoder الرموز < و> و& إلى \u003c و\u003e و\u0026، فيصبح JSON آمنًا للتضمين في HTML. ويعطّل SetEscapeHTML(false) ذلك. في معالجات HTTP يكون json.NewDecoder(r.Body).Decode(&v) وjson.NewEncoder(w).Encode(v) الثنائي المعتاد.

ترميز مخصّص

يستطيع النوع التحكّم في JSON الخاص به بتطبيق json.Marshaler وjson.Unmarshaler. حالة شائعة هي تعداد iota يجب أن يظهر كاسم لا كرقم:

لـ MarshalJSON مستقبِل قيمة فتعمل مع القيم والمؤشرات؛ أما UnmarshalJSON فتحتاج مستقبِل مؤشر لأنها تعدّل القيمة. الأنواع التي تحتاج شكلًا نصيًا فقط يمكنها تطبيق encoding.TextMarshaler (MarshalText) بدلًا من ذلك، وهذا يجعلها صالحة أيضًا كمفاتيح خرائط.

أخطاء شائعة

  • أسماء حقول بحروف صغيرة. تُتخطّى بصمت.
  • تمرير قيمة إلى Unmarshal. تحتاج مؤشرًا.
  • تجاهل الخطأ. JSON المشوّه وعدم تطابق الأنواع لا يُبلَّغ عنهما إلا عبره.
  • افتراض أن الأرقام في map[string]any من النوع int. إنها float64.
  • توقّع أن يُسقط omitempty بنية فارغة أو time.Time صفريًا. استخدم omitzero في Go 1.24، أو مؤشرًا.
  • الاعتماد على ترتيب الحقول في الخرائط. تُرتَّب مفاتيح الخرائط عند الإخراج؛ وتحتفظ حقول البنى بترتيب تعريفها.

الأسئلة الشائعة

كيف أحوّل بنية إلى JSON في Go؟

استدعِ json.Marshal(v)، التي تعيد []byte وخطأ. لا تُضمَّن إلا الحقول المُصدَّرة (الأسماء التي تبدأ بحرف كبير). استخدم وسم بنية مثل json:"name" على الحقل للتحكّم في مفتاحه في JSON. وللمخرجات المزاحة استخدم json.MarshalIndent(v, "", " ").

لماذا تختفي حقول بنيتي من مخرجات JSON؟

لا ترى encoding/json إلا الحقول المُصدَّرة. الحقل المسمّى name (بحرف صغير) غير مرئي لها، عند الترميز وعند فكّ الترميز. اجعل الحرف الأول كبيرًا واضبط مفتاح JSON بوسم مثل json:"name".

ماذا يفعل omitempty في JSON في Go؟

يُسقط omitempty الحقل من المخرجات عندما يحمل قيمة فارغة: false أو 0 أو "" أو مؤشرًا أو واجهة nil أو شريحة أو خريطة فارغة. ولا يعامل البنية أو time.Time كفارغة. أضافت Go 1.24 الخيار omitzero، الذي يُسقط أي قيمة تساوي القيمة الصفرية لنوعها (أو يعيد تابعها IsZero() القيمة true)، بما في ذلك البنى وtime.Time.

كيف أحلّل JSON ذا بنية مجهولة في Go؟

فكّ الترميز إلى map[string]any (أو any). تصبح الكائنات map[string]any، والمصفوفات []any، والنصوص string، والقيم المنطقية bool، وكل رقم float64. استخدم تأكيدات النوع لقراءة القيم، وDecoder.UseNumber إذا وجب أن تبقى الأعداد الصحيحة الكبيرة دقيقة.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن