اذهب إلى المحتوى

تُعَدّ المصفوفات Arrays والشرائح Slices في لغة جو بُنى بيانات تتألف من تسلسل مرتب من العناصر، وتكون هذه الأنواع من بُنى المعطيات ذات فائدة كبيرة عندما تعمل مع مجموعة من القيم التي ترتبط مع بعضها البعض بطريقة ما، كما أنها تسمح لك بالاحتفاظ بالبيانات المتشابهة أو ذات الصلة ببعضها معًا وتنفيذ العديد من العمليات عليها كلها أو على مجموعات جزئية منها ودفعةً واحدةً.

تتسم المصفوفات في لغة جو بأنها ثابتة الحجم، أي لن يكون بإمكانك تغيير ذلك بعد تحديد حجمها لأول مرة، فإذا صرّحت مثلًا عن مصفوفة a بعدد عناصر x، فستخصِّص جو لها ذاكرةً تتسع لعدد العناصر المُحدَّد x، وبالتالي لا يمكنك لاحقًا الإضافة إلى هذه المصفوفة أكثر من x عنصر، فصحيح أنّ ذلك يُفقدها المرونة، إلا أنه يجعلها أسرع.

وتتسم الشرائح في جو بكونها ديناميكيةً، مما يُتيح لك تغيير حجمها باستمرار أينما دعت الحاجة لذلك، وتعطي الخاصية الديناميكية المرونة العالية إلا أن ذلك يكون على حساب الأداء أو السرعة، وتُشبه الشرائح إلى حد كبير مفهوم القوائم Lists في لغة البرمجة بايثون والمصفوفات في أغلب اللغات الأخرى، ويمكنك في العديد من المواقف استخدام المصفوفات أو الشرائح، لكن في الحالات التي تحتاج فيها إلى زيادة أو تقليل عدد العناصر، فلا بد من استخدام الشرائح، لأنه في حالة المصفوفات لن تكون قادرًا على ذلك.

سيغطّي هذا المقال المصفوفات والشرائح بالتفصيل، كما سيزودك بالمعلومات الضرورية لاتخاذ القرار المناسب عند الاختيار بين أنواع البيانات هذه، وستراجع أيضًا الطرق الشائعة للتصريح والعمل مع كل من المصفوفات والشرائح.

المصفوفات

تُعَدّ المصفوفة بنية معطيات تجميعية تتألف من مجموعة من العناصر من النوع نفسه، وكل عنصر في المصفوفة يمكنه تخزين قيمة واحدة فيه.

تتميز عناصر المصفوفة عن بعضها من خلال عدد محدد يعطى لكل عنصر ويسمى فهرسًا index، بحيث يكون فهرس أول عنصر في المصفوفة 0 دائمًا، كما تُحدَّد سعة المصفوفة لحظة إنشائها، وبمجرد تعريف حجمها لا يمكن تغييره، وبما أنّ حجم المصفوفة ثابت، فهذا يعني أنه يخصص الذاكرة مرةً واحدةً فقط، مما يجعل المصفوفات غير مرنة نوعًا ما للعمل معها، لكنه يزيد من أداء برنامجك، لهذا السبب تُستخدَم المصفوفات عادةً عند تحسين البرامج.

تعريف المصفوفات

تُعرّف المصفوفات من خلال التصريح عن حجمها ضمن قوسين [ ] ثم نوع البيانات ثم القيم المحددة بين الأقواس المعقوصة { }.

[capacity]data_type{element_values}

مثال:

[3]string{"blue coral", "staghorn coral", "pillar coral"}

ملاحظة: تمثِّل كل مصفوفة تُعرّفها نوع بيانات مختلف بحد ذاته اعتمادًا على نوع البيانات data_type والحجم capacity، فالمصفوفة السابقة مثلًا من نوع string وحجمها 3، تختلف عن مصفوفة من نوع string وحجمها 2.

عندما تُصرّح عن مصفوفة بدون تهيئتها بقيم أوليّة، فستُعدّ لغة جو أنّ قيم جميع العناصر أصفار في حالة الأعداد وفي حالة السلاسل ''"، فالمصفوفة التالية مثلًا لم نحدد لها قيمًا أوليّةً، وبالتالي ستهيئها جو بأصفار على أساس قيم افتراضية:

var numbers [3]int

يكون الخرج كما يلي:

[0 0 0]

يمكنك أيضًا إسناد قيم عناصر المصفوفة عند إنشائها بوضعها ضمن قوسين معقوصين { } بالشكل التالي:

coral := [4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"}
fmt.Println(coral)

خزنا المصفوفة ضمن متغير ثم طبعنا قيمتها ويكون الخرج كما يلي:

[blue coral staghorn coral pillar coral elkhorn coral]

لاحظ أنه لا يوجد فصل واضح بين العناصر المطبوعة، لذا يُفضَّل استخدام الدالة ()fmt.Printf مع العنصر النائب q% لكي توضَع علامتَي اقتباس مزدوجة لكل عنصر لتحديده:

fmt.Printf("%q\n", coral)

يكون الخرج كما يلي:

["blue coral" "staghorn coral" "pillar coral" "elkhorn coral"]

وضعنا الرمز n\ للنزول سطر بعد طباعة المصفوفة.

فهرسة المصفوفات والشرائح

يمكن استدعاء عنصر محدد من المصفوفة أو الشريحة من خلال الفهرسة، إذ يمتلك كل عنصر فهرسًا والذي قيمته int تبدأ من الصفر وتزداد تصاعديًا.

سنستخدِم مصفوفةً في الأمثلة التالية، ولكن يمكنك أيضًا استخدام شريحة، إذ ستكون الفهرسة متطابقةً في كل منهما، فمن أجل المصفوفة coral ستكون الفهرسة كما يلي:

"blue coral" "staghorn coral" "pillar cora" "elkhorn coral"
3 2 1 0

لاحظ أنّ العنصر الأول blue coral يحمل الفهرس رقم 0 ويحمل العنصر الأخير elkhorn coral الفهرس رقم 3.

بما أن كل عنصر يمتلك فهرسًا خاصًا به، يمكننا الوصول إلى العنصر الذي نريده من خلال هذا الفهرس وإجراء العمليات عليه، فمثلًا نريد الآن الوصول إلى العنصر الثاني من المصفوفة:

fmt.Println(coral[1])

سيكون الخرج كما يلي:

staghorn coral

كما يمكنك بالطريقة ذاتها الوصول إلى أيّ عنصر من المصفوفة:

coral[0] = "blue coral"
coral[1] = "staghorn coral"
coral[2] = "pillar coral"
coral[3] = "elkhorn coral"

لاحظ أن هناك 4 عناصر في المصفوفة، وبالتالي تكون الفهارس من 0 إلى 3، لذا لا تحاول وضع فهرس خارج هذه الحدود، فإذا حاولت مثلًا في المصفوفة السابقة الوصول إلى عنصر يحمل الفهرس 4 أو 5 أو 18، فسيظهر لك خطأ لأن هذا العنصر غير موجود أو أنك تتجاوز حدود المصفوفة:

fmt.Println(coral[18])

يكون الخرج كما يلي:

panic: runtime error: index out of range

في العديد من لغات البرمجة الأخرى مثل بايثون، يمكنك الوصول للعناصر من خلال الفهرسة السلبية، لكن لا يمكنك ذلك في جو، أي يجب استخدام الأعداد الموجبة للوصول إلى العناصر، وإلا سيظهر لك خطأ كما في المثال التالي:

fmt.Println(coral[-1])

يكون الخرج كما يلي:

invalid array index -1 (index must be non-negative)

يمكنك ضم عناصر سلسلة في مصفوفة أو شريحة مع سلاسل أخرى باستخدام العامل +:

fmt.Println("Sammy loves " + coral[0])

يكون الخرج كما يلي:

Sammy loves blue coral

تمكنا من وصل العنصر الموجود في الفهرس رقم 0 بالسلسلة النصية Sammy loves، لأن كل عنصر في المصفوفة هو سلسلة نصية بحد ذاته بما أننا حددنا نوع بيانات المصفوفة على أنه string وبالتالي كل عنصر فيها يُمثّل سلسلةً نصيةً.

يمكننا الوصول إلى كل عنصر بصورة منفصلة والعمل مع تلك العناصر باستخدام أعداد الفهرس التي تتوافق مع العناصر داخل مصفوفة أو شريحة ما.

تعديل عناصر المصفوفة

يمكنك تعديل قيمة عنصر محدَّد ضمن المصفوفة بالطريقة نفسها التي تُعدّل فيها قيمة متغير من أيّ نوع بيانات وذلك بعد الوصول إلى ذلك العنصر من خلال رقم الفهرس الخاص به، ويمنحنا هذا مزيدًا من التحكم في البيانات الموجودة في الشرائح والمصفوفات، كما سيسمح لنا بمعالجة العناصر الفردية برمجيًا.

coral[1] = "foliose coral"

سنطبع الآن المصفوفة لنرى التعديل:

fmt.Printf("%q\n", coral)

يكون الخرج كما يلي:

["blue coral" "foliose coral" "pillar coral" "elkhorn coral"]

معرفة حجم المصفوفة

الآن بعد أن عرفت كيفية التعامل مع العناصر الفردية لمصفوفة أو شريحة، دعنا نلقي نظرةً على دالتين ستمنحانك مزيدًا من المرونة عند العمل مع بُنى المعطيات هذه. الدالة الأولى هي ()len وهي دالة مُضمّنة في جو تساعدك على العمل مع المصفوفات والشرائح، بحيث نُمرر لهذه الدالة المصفوفة أو الشريحة وتعيد لنا عدد عناصرها كما في المثال التالي:

len(coral)

سيكون الخرج 4 لأن عدد العناصر في المصفوفة هو 4.

مثال آخر، سننشئ مصفوفة أعداد صحيحة ونحسب عدد عناصرها:

numbers := [13]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
fmt.Println(len(numbers))

يكون الخرج كما يلي:

13

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

إضافة عناصر إلى مصفوفة

الدالة الأخرى التي سنتعرّف عليها هي ()append وهي خاصة بالشرائح، إذ تضيف هذه الدالة عنصرًا جديدًا إلى الشريحة، ولا يمكن استخدام هذه الدالة مع المصفوفات لأن المصفوفات لا يمكن تغيير حجمها ببساطة كما سبق وذكرنا، فلتكن لدينا المصفوفة التالية على سبيل المثال:

coral := [4]string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral"}

إذا حاولت إضافة عنصر جديد black coral إلى هذه المصفوفة من خلال الدالة ()append:

coral = append(coral, "black coral")

ستحصل على خطأ:

first argument to append must be slice; have [4]string

ولحل هذه المشكلة، سنلجأ إلى نوع بيانات آخر وهو الشرائح.

الشرائح

تُعَدّ الشريحة تسلسلًا مرتبًا من العناصر والتي يمكن أن يتغير طولها (قابلة للتغيير)، حيث يمكن للشرائح أن تزيد حجمها ديناميكيًا، فعند إضافة عناصر جديدة إلى شريحة وإذا لم يكن للشريحة حجم ذاكرة كافي لتخزين العناصر الجديدة، فستطلب ذاكرةً أكبر من النظام حسب الحاجة، ولهذا السبب هي شائعة الاستخدام أكثر من المصفوفات.

تمكّنك الخاصيّة الديناميكية للشرائح من العمل معها في الحالات التي تحتاج فيها إلى تغيير طول عدد عناصر البيانات بأمان، وهذه هي الخاصية الوحيدة التي تتميز بها الشرائح عن المصفوفات.

التصريح عن شريحة

يُصرّح عن الشرائح من خلال تحديد نوع البيانات مسبوقًا بقوسَي فتح وإغلاق مربعَين [] ليس فيهما أي قيمة -خلاف نوع المصفوفة التي تحتاج إلى تحديد حجمها- وقيم بين أقواس معقوصة {}. وتكون شريحة من الأعداد الصحيحة كما يلي:

[]int{-3, -2, -1, 0, 1, 2, 3}

شريحة من الأعداد الحقيقية:

[]float64{3.14, 9.23, 111.11, 312.12, 1.05}

شريحة من السلاسل:

[]string{"shark", "cuttlefish", "squid", "mantis shrimp"}

يمكنك أيضًا إسنادها إلى متغير:

seaCreatures := []string{"shark", "cuttlefish", "squid", "mantis shrimp"}

ثم طباعة هذا المتغير:

fmt.Println(seaCreatures)

يكون الخرج كما يلي:

[shark cuttlefish squid mantis shrimp]

مثال آخر:

seaCreatures := []string{"shark", "cuttlefish", "squid", "mantis shrimp", "anemone"}

سنطبع الشريحة لكن باستخدام الدالة ()fmt.Printf مع العنصر النائب q% كما فعلنا مع المصفوفات سابقًا:

fmt.Printf("%q\n", seaCreatures)

يكون الخرج كما يلي:

["shark" "cuttlefish" "squid" "mantis shrimp" "anemone"]

إذا رغبت في إنشاء شريحة بطول معيّن دون تحديد عناصرها، فيمكنك استخدام الدالة ()make المضمنة:

oceans := make([]string, 3)

فإذا طبعناها، فسيكون الخرج كما يلي:

["" "" ""]

يمكنك أيضًا إنشاء شريحة بطول محدَّد كما فعلنا أعلاه لكن مع حجز مساحة إضافية من خلال تمرير عدد العناصر التي نريد حجز ذاكرة لها بصورة استباقية على أساس وسيط ثالث:

oceans := make([]string, 3, 5)

المقصود هنا أنه ستُنشأ شريحة بطول 3 لكن ستُحجز ذاكرة لخمس عناصر إضافية، أي ستحجز بالمجمل 8 عناصر، والهدف من ذلك هو تحسين الأداء، أي نتوقع أنه ستُضاف 5 عناصر على الأكثر لاحقًا، فنحجز لهم ذاكرةً مسبقًا لتجنب التأخير الذي سيحدث عند حجز ذاكرة إضافية في وقت تشغيل البرنامج بحيث نستفيد من الخاصية الديناميكية والأداء كما في المصفوفات.

يمكنك استخدام الدالة ()append التي تحدثنا عنها سابقًا لإضافة عنصر جديد إلى الشريحة.

تقطيع المصفوفات

تدعم المصفوفات إضافةً إلى الفهرسة عملية الاقتطاع slicing أيضًا، إذ تُستخدم الفهرسة للحصول على عناصر مفردة؛ أما عملية الاقتطاع فتتيح الحصول على جزء من المصفوفة، أي عدة عناصر متتالية، ويمكنك إجراء ذلك عن طريق إنشاء نطاق من أرقام الفهرس مفصولةً بنقطتين على صورة [الفهرس الأول: الفهرس الثاني] أو [first_index:second_index]، ومن المهم ملاحظة أنه عند تقطيع المصفوفة ستكون النتيجة شريحةً وليست مصفوفةً.

لنفترض أنك ترغب فقط في طباعة العناصر الوسطى من المصفوفة coral بدون العنصر الأول والأخير، إذ يمكنك إجراء ذلك عن طريق إنشاء شريحة تبدأ من الفهرس 1 وتنتهي قبل الفهرس 3 مباشرةً كما يلي:

fmt.Println(coral[1:3])

يكون الخرج كما يلي:

[foliose coral pillar coral]

لاحظ أننا وضعنا الرقم 1 ثم نقطتين ثم 3، بالنسبة للرقم 1 فقد وضعناه لأنه يمثّل نقطة البداية حيث يتواجد ثاني عنصر من المصفوفة؛ أما 3 فهو نقطة النهاية لكنها لا تؤخذ، وإنما تؤخذ القيمة التي قبلها مباشرةً، أي أنه ستؤخذ العناصر من 1 إلى 2، باختصار، العنصر المُحدد بالرقم الأول سيكون مشمولًا دائمًا بعملية الاقتطاع؛ أما العنصر المُحدد بالرقم الأخير فلن يكون مشمولًا.

هناك بعض القيم الافتراضية المفيدة في خاصية التقطيع، فإذا حُذف الفهرس رقم 1 first_index -أي العنصر الثاني-، فستكون القيمة الافتراضية له صفرًا، وإذا حُذف الرقم الثاني second_index فإنّ القيمة الافتراضية تكون طول السلسلة النصية التي سيجري اقتطاعها.

coral[:2]   // اقتطاع العناصر من الموقع 0 إلى الموقع 2 (غير مشمول)‏
coral[1:]   // اقتطاع العناصر من الموقع 1 (مشمول) إلى نهاية السلسلة

نريد مثلًا من أول عنصر حتى العنصر الثاني:

fmt.Println(coral[:3])

يكون الخرج كما يلي:

[blue coral foliose coral pillar coral]

أو مثلًا نريد من العنصر الأول حتى النهاية:

fmt.Println(coral[1:])

يكون الخرج كما يلي:

[foliose coral pillar coral elkhorn coral]

التحويل من مصفوفة إلى شريحة

في حال احتجت إلى تغيير حجم المصفوفة يمكنك تحويلها إلى شريحة من خلال الآلية التي اتبعناها في الفقرة السابقة لتقطيع المصفوفة، ويمكن إنجاز ذلك من خلال استخدام النقطتين : بدون تحديد البداية أو النهاية، أي كما يلي:

coral[:]

لاحظ أنه هنا لا يُحوّل المُتغير بحد ذاته -والذي يمثّل المصفوفة- إلى شريحة، لكن ما يحدث هو أنه عند استخدامك للتقطيع مع المصفوفات، ستُعيد جو نسخةً تمثّل الجزء الذي اقتطعته على أساس شريحة، أي أنّ المتغير coral نفسه لا يحوّل، وإنما تُعاد نسخة منه، وهذا منطقي، ففي جو لا يمكنك تغيير نوع المتغير مهما كان نوعه، إذًا نكتب كما يلي:

coralSlice := coral[:]

إذًأ ستمثّل coralSlice نسخة شريحة من المصفوفة coral، فإذا طبعناها، فسنحصل على ما يلي:

[blue coral foliose coral pillar coral elkhorn coral]

يمكنك الآن مثلًا إضافة عنصر جديد وليكن black coral إلى الشريحة كما يلي:

coralSlice = append(coralSlice, "black coral")
fmt.Printf("%q\n", coralSlice)

سنحصل على الخرج التالي عند طباعتها:

["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral"]

يمكنك أيضًا إضافة أكثر من عنصر دفعةً واحدةً:

coralSlice = append(coralSlice, "antipathes", "leptopsammia")

يكون الخرج كما يلي:

["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia"]

يمكنك دمج شريحتين معًا من خلال ()append لكن يجب أن تضع ثلاث نقاط ... بعد اسم الشريحة الثانية كما يلي:

moreCoral := []string{"massive coral", "soft coral"}
coralSlice = append(coralSlice, moreCoral...)

يكون الخرج كما يلي:

["blue coral" "foliose coral" "pillar coral" "elkhorn coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]

حذف عنصر من شريحة

لا تمتلك جو دوالًا جاهزةً مثل باقي اللغات لحذف عنصر، إذ يجب عليك الاعتماد على مبدأ التقطيع لحذف العناصر، فلحذف عنصر يجب عليك تقطيع الشريحة لشريحتين، بحيث تمثِّل الأولى جميع العناصر التي قبله وتمثِّل الثانية العناصر الذي بعده، ثم دمج هاتين الشريحتين الجديدتين معًا بدون العنصر الذي تريد حذفه، أي كما يلي بفرض أنّ i هو فهرس العنصر المراد إزالته:

slice = append(slice[:i], slice[i+1:]...)

نريد فرضًا حذف العنصر elkhorn coral الموجود في الفهرس 3 من الشريحة coralSlice:

coralSlice := []string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral", "black coral", "antipathes", "leptopsammia", "massive coral", "soft coral"}

coralSlice = append(coralSlice[:3], coralSlice[4:]...)

fmt.Printf("%q\n", coralSlice)

يكون الخرج كما يلي:

["blue coral" "foliose coral" "pillar coral" "black coral" "antipathes" "leptopsammia" "massive coral" "soft coral"]

نلاحظ أنّ العنصر الذي حددناه قد حُذف من الشريحة، ويمكنك أيضًا حذف عدة قيم أو مجال من القيم دفعةً واحدةً، إذ تريد مثلًا حذف "elkhorn coral" و "black coral" و "antipathes"، أي تريد حذف العناصر الموجودة في الفهارس 3 و 4 و 5:

coralSlice := []string{"blue coral", "foliose coral", "pillar coral", "elkhorn coral", "black coral", "antipathes", "leptopsammia", "massive coral", "soft coral"}

coralSlice = append(coralSlice[:3], coralSlice[6:]...)

fmt.Printf("%q\n", coralSlice)

يكون الخرج كما يلي:

["blue coral" "foliose coral" "pillar coral" "leptopsammia" "massive coral" "soft coral"]

عدد عناصر الشريحة

صحيح أنه يمكنك استخدام التابع ()len لمعرفة عدد عناصر الشريحة، لكنه سيعطيك عدد العناصر الظاهرة وليس عدد العناصر التي حُجز لها مكان في الذاكرة، وللتوضيح، يجب عليك العودة إلى الدالة ()make وتتذكر حينما كتبنا:

oceans := make([]string, 3, 5)

هنا أنشأنا شريحة عدد عناصرها الظاهر 3 لكن حجزنا ذاكرة لخمسة عناصر وقد شرحنا ذلك سابقًا، فإذا استخدمنا الآن الدالة ()len لمعرفة عدد عناصر الشريحة oceans، فستُعيد 3؛ أما إذا استخدمنا الدالة ()cap، فستعطي 5 وهذا هو الفرق الوحيد بينهما.

لاحظ أن الدالة ()cap ليس لاستخدامها معنًى مع المصفوفات لأن الحجم ثابت، أي الحجم الظاهر هو نفسه المحجوز دومًا، لذا اقتصر تعريف ()cap على العمل مع الشرائح ولا تعمل مع المصفوفات.

الاستخدام الشائع للدالة ()cap هو إنشاء شريحة بعدد محدد مسبقًا من العناصر ثم ملء تلك العناصر برمجيًا، إذ يؤدي ذلك إلى تجنب عمليات التخصيص غير الضرورية المحتملة التي قد تحدث باستخدام ()append لإضافة عناصر تتجاوز السعة المخصصة حاليًا كما في المثال التالي:

numbers := []int{}
for i := 0; i < 4; i++ {
    numbers = append(numbers, i)
}
fmt.Println(numbers)

يكون الخرج كما يلي:

[0 1 2 3]

أنشأنا شريحةً ثم أنشأنا حلقة for تتكرر أربع مرات. أضفنا في كل تكرار القيمة الحالية لمتغير الحلقة i إلى شريحة الأعداد numbers، وقد يؤدي ذلك إلى عمليات تخصيص غير ضرورية للذاكرة والتي قد تؤدي إلى إبطاء برنامجك، فعند إضافة عناصر إلى شريحة فارغة، فإنه في كل مرة تستدعي فيها الدالة ()append تتحقق جو من سعة الشريحة، فإذا كان العنصر المضاف سيجعل الشريحة تتجاوز هذه السعة، فستُخصص ذاكرة إضافية لها، مما يؤدي إلى إنشاء عبء إضافي في برنامجك ويمكن أن يؤدي إلى إبطاء التنفيذ.

سنملأ الآن الشريحة بدون استخدام ()append وذلك عن طريق التخصيص المسبق للعناصر كما تعلمت سابقًا في بداية المقال:

numbers := make([]int, 4)
for i := 0; i < cap(numbers); i++ {
    numbers[i] = i
}

fmt.Println(numbers)

يكون الخرج كما يلي:

[0 1 2 3]

استخدمنا هنا الدالة ()make لإنشاء شريحة وجعلناها تخصص 4 عناصر مسبقًا، ثم استخدمنا بعد ذلك الدالة ()cap في الحلقة للتكرار على كل عنصر من الشريحة (العناصر تكون كلها أصفار كما أشرنا سابقًا)، ثم ملأنا الشريحة بالقيم التي نريدها وهي قيم متغير الحلقة i، ولاحظ أنّ استخدام الدالة ()cap هنا بدلًا من ()append سيتجنب أيّ تخصيصات إضافية للذاكرة.

الشرائح متعددة الأبعاد

يمكنك أيضًا تعريف الشرائح متعددة الأبعاد، أي شريحة تتضمّن شريحةً أو أكثر؛ يمكن القول شرائح متداخلة، إذ نضع هنا الشرائح ضمن قوسين داخل الشريحة التي تضمها. مثال:

seaNames := [][]string{{"shark", "octopus", "squid", "mantis shrimp"}, {"Sammy", "Jesse", "Drew", "Jamie"}}

يجب عليك استخدام عدة مؤشرات للوصول إلى عنصر داخل هذه الشريحة، بحيث نستخدِم مؤشرًا واحدًا لكل بُعد من أبعاد البنية:

fmt.Println(seaNames[1][0])
fmt.Println(seaNames[0][0])

تعني التعليمة [seaNames[1][0 أنك تريد الوصول إلى العنصر الأول 0 من الشريحة ذات الفهرس 1؛ أما التعليمة الثانية، فتشير إلى أنك تريد الوصول إلى العنصر الأول 0 من الشريحة ذات الفهرس 0، لذا سيكون الخرج كما يلي:

Sammy
shark

فيما يلي قيم الفهرس لبقية العناصر الفردية:

seaNames[0][0] = "shark"
seaNames[0][1] = "octopus"
seaNames[0][2] = "squid"
seaNames[0][3] = "mantis shrimp"

seaNames[1][0] = "Sammy"
seaNames[1][1] = "Jesse"
seaNames[1][2] = "Drew"
seaNames[1][3] = "Jamie"

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

الخاتمة

تعلمت في هذا المقال كيفية العمل مع المصفوفات والشرائح والروابط في جو، وتعرّفت على العديد من حالات الاستخدام لكل منها، كما تعرّفت على بعض الأخطاء الشائعة في التعامل مع هذه البُنى وعلى دوال أساسية فيها، وأصبحت لديك القدرة أيضًا على التفريق بين الشرائح والمصفوفات ومتى تستخدم أيًا منهما.

ترجمة -وبتصرف- للمقال Understanding Arrays and Slices in Go لصاحبه Gopher Guides.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...