تعريف مصفوفة
يُكتب نوع المصفوفة (array) بالشكل [N]T: الطول ثم نوع العنصر. الطول ثابت وقت الترجمة وهو جزء من النوع.
المخرجات:
[90 0 0 0 75] 5
Tue
[5]int [2 3 5 7 11]
["" "b" "" "d" ""]
المصفوفة مهيّأة بالكامل دائمًا. العناصر التي لا تضبطها تحمل القيمة الصفرية لنوع العنصر: 0 أو "" أو false أو nil.
الفهرسة وحدود المصفوفة
تمتد الفهارس من 0 إلى len(a)-1. الفهرس الثابت الخارج عن النطاق خطأ ترجمة، أما الفهرس المتغيّر الخارج عن النطاق فيسبّب panic وقت التشغيل.
var a [3]int
a[5] = 1 // compile error: invalid argument: index 5 out of bounds [0:3]
i := 5
a[i] = 1 // panic: runtime error: index out of range [5] with length 3
المرور على العناصر
تزور for i, v := range a كل عنصر بالترتيب. المتغيّر v نسخة من العنصر، لذا الإسناد إلى v لا يغيّر المصفوفة. اكتب عبر الفهرس بدلًا من ذلك.
وهناك دقيقة إضافية خاصة بالمصفوفات: range على قيمة مصفوفة يقيّم نسخة منها في البداية. إذا عدّل جسم الحلقة عناصر لاحقة، يبقى v يعرض القيم القديمة. المرور على &a أو a[:] يتجنّب هذه النسخة.
المصفوفات قيم
هذا هو الفرق الأساسي عن المصفوفات في C أو Java أو JavaScript. إسناد مصفوفة ينسخ كل عناصرها، وتمريرها إلى دالة ينسخها أيضًا.
المخرجات:
[1 2 3] [99 2 3]
[1 2 3]
[0 2 3]
النسخ رخيص للمصفوفات الصغيرة ومكلف للكبيرة: تمرير [1_000_000]int بالقيمة ينسخ ثمانية ميغابايت. مرّر مؤشرًا (*[N]T) أو شريحة (a[:]) عندما تكون المصفوفة كبيرة أو تحتاج الدالة إلى تعديلها. الفهرسة عبر مؤشر مصفوفة لا تحتاج * صريحة: a[0] تعمل على *[3]int.
مقارنة المصفوفات واستخدامها مفاتيح للخرائط
تدعم مصفوفات العناصر القابلة للمقارنة == و!=. تتساوى مصفوفتان عندما يتساوى كل عنصر فيهما. وهذا يجعلها أيضًا مفاتيح صالحة للخرائط (maps)، بخلاف الشرائح.
المصفوفات مختلفة الطول أنواع مختلفة ولا يمكن مقارنتها أصلًا: [3]int{} == [4]int{} لا تُترجم (mismatched types [3]int and [4]int).
المصفوفات متعددة الأبعاد
مصفوفة من المصفوفات تعطيك شبكة ثابتة. الشبكة كلها كتلة واحدة متصلة في الذاكرة.
تحوّل row[:] الصف من النوع [3]rune إلى شريحة []rune، وهي ما تقبله string().
المصفوفات مقابل الشرائح
المصفوفة [N]T | الشريحة []T | |
|---|---|---|
| الطول | ثابت، جزء من النوع | يتغيّر مع append |
| الإسناد والتمرير | ينسخ كل العناصر | ينسخ ترويسة صغيرة ويشارك العناصر |
| القيمة الصفرية | N عنصرًا صفريًا | nil، بطول 0 |
== | نعم، عنصرًا بعنصر | فقط مع nil |
| مفتاح خريطة | نعم | لا |
| الاستخدام المعتاد | بيانات ثابتة الحجم: قيم التجزئة، الإحداثيات، المخازن المؤقتة | تقريبًا كل ما عدا ذلك |
عمليًا ستقابل المصفوفات في أماكن قليلة: تعيد sha256.Sum256 قيمة [32]byte، وجداول البحث التي لا يتغيّر حجمها، وكمخزن خلفي لشريحة. تقطيع مصفوفة بـ a[:] أو a[1:3] ينشئ شريحة تشاركها الذاكرة؛ صفحة الشرائح تشرح ما تعنيه هذه المشاركة.
التحويل بين المصفوفات والشرائح
تحويل شريحة إلى مصفوفة (Go 1.20) أو إلى مؤشر مصفوفة (Go 1.17) يسبّب panic إذا كانت الشريحة أقصر من طول المصفوفة: panic: runtime error: cannot convert slice with length 2 to array or pointer to array with length 3.
أخطاء شائعة
- توقّع أن تعدّل الدالة مصفوفة مُرّرت إليها. الدالة تتلقّى نسخة. مرّر
*[N]Tأو شريحة. - استخدام مصفوفة حيث تُطلب شريحة.
[]int{1, 2}شريحة، و[2]int{1, 2}مصفوفة. الدالة التي تأخذ[]intلن تقبل[2]int؛ مرّرa[:]. - المصفوفات الكبيرة في حلقة range.
for _, v := range bigArrayتنسخ المصفوفة كلها أولًا. مرّ على&bigArrayأو على شريحة.
الأسئلة الشائعة
كيف تعرّف مصفوفة في Go؟
اكتب الطول بين قوسين معقوفين قبل نوع العنصر: var a [5]int تنشئ خمسة أصفار. ومع القيم: a := [3]string{"x", "y", "z"}. استخدم [...] ليعدّ المترجم العناصر بنفسه: a := [...]int{1, 2, 3} نوعها [3]int.
ما الفرق بين المصفوفة والشريحة في Go؟
للمصفوفة طول ثابت هو جزء من نوعها ([3]int و[4]int نوعان مختلفان)، وتُنسخ عند إسنادها أو تمريرها. أما الشريحة ([]int) فهي نافذة على مصفوفة أساسية، طولها يتغيّر عبر append، ونسخ الشريحة ينسخ النافذة فقط لا العناصر. معظم شيفرات Go تستخدم الشرائح.
كيف أحصل على طول مصفوفة في Go؟
استخدم الدالة المدمجة len(a). طول المصفوفة ثابت يُعرف وقت الترجمة، لذا يمكنك استعماله في التعابير الثابتة. وتعيد cap(a) الرقم نفسه.
هل يمكن مقارنة المصفوفات في Go؟
نعم، باستخدام == و!= إذا كان نوع العنصر قابلًا للمقارنة. تتساوى مصفوفتان عندما تتساوى كل عناصرهما. ويمكن أيضًا استخدام المصفوفات مفاتيح في الخرائط. أما الشرائح فلا تُقارن بـ == (إلا مع nil)؛ استخدم لها slices.Equal.