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

البنى Struct في Golang: التعريف والتهيئة والمقارنة والوسوم

تجمع البنى (structs) حقولًا مسمّاة في نوع واحد. تعلّم كيف تعرّفها وتهيّئها، والقيم الصفرية، والمؤشرات إلى البنى، والبنى المجهولة، والمقارنة، ووسوم البنى، واصطلاح دالة البناء NewX.

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

تعريف بنية وإنشاؤها

نوع البنية (struct) قائمة من الحقول المسمّاة. تعرّفه بـ type Name struct { ... } وتنشئ القيم بحرفية مركّبة.

المخرجات:

Ana 31
{Name:Ana Email:ana@example.com Age:32 Admin:false}
{Name: Email: Age:0 Admin:false}
main.User{Name:"Bob", Email:"", Age:0, Admin:false}

يطبع %+v أسماء الحقول ويطبع %#v صيغة Go. كلاهما أسرع طريقة لفحص بنية أثناء تتبّع الأخطاء.

يمكن للحقول من النوع نفسه أن تتشارك سطرًا: X, Y float64. أسماء الحقول التي تبدأ بحرف كبير مُصدَّرة (مرئية للحزم الأخرى ولـ encoding/json)؛ والتي تبدأ بحرف صغير ليست كذلك.

أشكال الحرفيات

User{Name: "Ana", Age: 31}        // named fields: order-free, omitted fields are zero
User{"Ana", "a@x.com", 31, false} // positional: every field, in order
&User{Name: "Ana"}                // pointer to a new struct
new(User)                         // pointer to a zeroed struct

فضّل الحقول المسمّاة. تنكسر الحرفيات الموضعية عندما يضيف أحدهم حقلًا أو يعيد ترتيب الحقول، ويحذّر go vet منها لأنواع البنى من حزم أخرى (مثلًا net/url.Error struct literal uses unkeyed fields). الشكل الموضعي لا بأس به للأنواع المحلية الصغيرة مثل Point{1, 2}.

لا قيم افتراضية: القيم الصفرية ودوال البناء

لا تملك Go قيمًا افتراضية للحقول ولا دوال بناء في اللغة. يبدأ كل حقل بالقيمة الصفرية لنوعه: 0 و"" وfalse وnil. أسلوبان يسدّان الفجوة.

اجعل القيمة الصفرية مفيدة. تعمل sync.Mutex وbytes.Buffer وstrings.Builder كلها دون تهيئة. عندما تستطيع تصميم نوع بهذه الطريقة، افعل.

اكتب دالة NewX عندما يحتاج حقل قيمة افتراضية غير صفرية أو يجب حجز شيء ما، مثل خريطة:

تعيد NewServer مؤشرًا لأن للخادم توابع تعدّله وسيُشارك. وإعادة البنية بالقيمة شائعة أيضًا للأنواع الصغيرة غير القابلة للتعديل (تعيد time.Date قيمة time.Time).

المؤشرات إلى البنى

تلغي Go مرجعية مؤشرات البنى تلقائيًا عند الوصول إلى الحقول. مع p := &User{} تكتب p.Name، لا (*p).Name.

المخرجات:

{11 12}
{11 12} {0 12}
{11 0}

البنى قيم. الإسناد ووسائط الدوال تنسخها؛ والمؤشر يشارك واحدة. والنسخ حقلًا بحقل سطحي: حقل الشريحة أو الخريطة في النسخة ما زال يشير إلى البيانات نفسها. راجع المؤشرات لتعرف متى تستخدم كلًا منهما.

البنى المجهولة

يمكن كتابة نوع بنية في مكانه دون اسم. هذا مفيد للتجميعات لمرة واحدة، والاختبارات المبنية على الجداول، وفكّ ترميز JSON تقرؤه مرة واحدة.

جدول []struct{ in string; want int } هو الشكل المعتاد لاختبار في Go.

مقارنة البنى

البنى قابلة للمقارنة بـ == عندما يكون كل حقل قابلًا للمقارنة. والمساواة تعني تساوي كل الحقول. ويمكن للبنى القابلة للمقارنة أن تكون مفاتيح خرائط أيضًا.

لبنية فيها حقول شرائح أو خرائط، اكتب تابع Equal أو قارن في الاختبارات بـ reflect.DeepEqual.

وسوم البنى

الوسم حرفية نصية بعد نوع الحقل. تتجاهله اللغة؛ وتقرؤه المكتبات بالانعكاس. أشيع قارئ له هو encoding/json:

يطبع هذا {"id":7,"name":"Mug"}: يعيد الوسم تسمية الحقول، ويُسقط omitempty الحقل Price الصفري، والحقل غير المُصدَّر غير مرئي للمرمّز. تتبع الوسوم اصطلاح key:"value"، مع عدة مفاتيح مفصولة بمسافات: `json:"name" db:"user_name"`. الوسم المشوّه يُترجم بلا مشكلة ويُتجاهل بصمت، ويكتشفه go vet. صفحة json تشرح الخيارات.

البنى الفارغة وترتيب الحقول

ليس لـ struct{} أي حقول وتشغل صفر بايت. تُستخدم كقيمة مجموعة (map[string]struct{}) وكإشارة على القنوات (chan struct{})، حيث يهمّ الحدث وحده.

يؤثّر ترتيب الحقول في تخطيط الذاكرة: يحشو المترجم الحقول حسب محاذاتها. بنية من bool, int64, bool تشغل 24 بايتًا على أنظمة 64 بت، بينما int64, bool, bool تشغل 16. هذا يهمّ فقط للأنواع المخزّنة بأعداد كبيرة.

أخطاء شائعة

  • تعديل نسخة. for _, u := range users { u.Age++ } تغيّر نسخة في كل مرة. استخدم الفهرس: users[i].Age++.
  • نسيان تهيئة حقل خريطة. القيمة الصفرية للبنية تحمل خريطة nil؛ والكتابة فيها تسبّب panic. احجزها في دالة بناء.
  • نسخ بنية تحمل sync.Mutex. للنسخة حالة قفل خاصة بها. مرّر هذه البنى بمؤشر؛ ويبلغ go vet عن النسخ.
  • الحرفيات الموضعية لأنواع حزم أخرى. تنكسر عند إضافة حقل.

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

كيف تهيّئ بنية في Go؟

بحرفية مركّبة. الحقول المسمّاة هي الشكل المعتاد: u := User{Name: "Ana", Age: 31}، وأي حقل تحذفه يأخذ قيمته الصفرية. تعطي User{} كل القيم الصفرية، و&User{...} مؤشرًا، وnew(User) مؤشرًا إلى بنية صفرية.

هل تدعم Go قيمًا افتراضية لحقول البنى؟

لا. يبدأ كل حقل بالقيمة الصفرية لنوعه. الأسلوب المعتاد دالة بناء، func NewServer() *Server { return &Server{Port: 8080} }، أو تصميم النوع بحيث تكون قيمته الصفرية مفيدة أصلًا، كما في sync.Mutex وbytes.Buffer.

كيف تقارن بنيتين في Go؟

بـ ==، إذا كان كل حقل قابلًا للمقارنة. تتساوى قيمتا بنية عندما تتساوى كل الحقول المتقابلة. البنية التي تحتوي حقل شريحة أو خريطة أو دالة لا يمكن مقارنتها بـ == (خطأ ترجمة)؛ قارن الحقول بنفسك أو استخدم reflect.DeepEqual في الاختبارات.

ما هي وسوم البنى في Go؟

حرفيات نصية بعد نوع الحقل، مثل `json:"name,omitempty"`. يتجاهلها المترجم؛ وتقرؤها بالانعكاس حزم مثل encoding/json ومشغّلات قواعد البيانات وأدوات التحقّق للتحكّم في طريقة ترميز الحقول أو تسميتها أو فحصها.

كيف أطبع بنية مع أسماء حقولها في Go؟

استخدم fmt.Printf("%+v\n", s)، التي تطبع {Name:Ana Age:31}. يطبع %v القيم فقط، ويطبع %#v صيغة Go مع اسم النوع: main.User{Name:"Ana", Age:31}.

Coddy programming languages illustration

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

ابدأ الآن