الأساسيات

الشرائح Slices

الشرائح Slices في لغة غو هي طريقة مناسبة وقوية, تعتمد على المصفوفات Arrays, الشرائح لاتمتلك بيانات data بحد ذاتها, وانما بياناتها هم مجرد مراجع/مؤشرات references/pointers لبيانات مصفوفة ما.

مثال

package main

import (
"fmt"
)

func main() {
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4]
fmt.Println(b)
}

العبارة التالية

a[start:end]

تُستخدم لانشاء شريحة من مصفوفة, بادئةً من الفهرس start الى الفهرس end-1 .
ولذلك في السطر التاسع من المثال السابق, أنشئنا شريحة من المصفوفة a, حيث تبدأ من الفهرس رقم 1 حتى الفهرس رقم 4 (أي 3 عناصر) وبذلك تكون عناصر الشريحة

[77 78 79]

ويوجد طريقة اخرى مختصرة لانشاء الشرائح من المصفوفات كما في المثال التالي

package main

import (
"fmt"
)

func main() {
c := []int{6, 7, 8}
fmt.Println(c)
}

في السطر التاسع, أنشئنا مصفوفة من 3 عناصر ولكنها ستُعاد لنا على أنها شريحة Slice .

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

مثال

package main

import (
"fmt"
)

func main() {
darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
dslice := darr[:5]
fmt.Println("array before", darr)
for i := 0; i 

في السطر الثامن أنشئنا مصفوفة darr
وفي السطر التاسع أنشئنا شريحة dslice تعتمد على أول 5 عناصر من المصفوفة darr
ومن خلال حلقة for على عناصر الشريحة dslice قمنا بتعديل قيمة كل عنصر من الشريحة (ضربناه بالرقم 10)
وعند تنفيذ البرنامج, سنلاحظ أن قيم عناصر المصفوفة darr قد تعدلت أيضاً
ونتيجة تنفيذ المثال ستكون

array before [57 89 90 82 100 78 67 69 59]
array after [570 890 900 820 1000 78 67 69 59]

مثال آخر

package main

import (
"fmt"
)

func main() {
numa := [3]int{78, 79 ,80}
nums1 := numa[:]
nums2 := numa[:]
fmt.Println("array before change 1",numa)
nums1[0] = 100
fmt.Println("array after modification to slice nums1", numa)
nums2[1] = 101
fmt.Println("array after modification to slice nums2", numa)
}

ملاحظة: اذا لم نحدد عدد عناصر الشريحة [:], فالشريحة ستأخذ جميع عناصر المصفوفة.

نتيجة المثال ستكون

array before change 1 [78 79 80]
array after modification to slice nums1 [100 79 80]
array after modification to slice nums2 [100 101 80]
  • طول الشريحة ومدى استيعابها Slice Length & Capacity

طول الشريحة أي عدد عناصرها Elements, أما مدى استيعاب الشريحة فهو عدد عناصر المصفوفة التي تم الاعتماد عليها (أخذ العناصر منها) بدءاً من فهرس الذي تم تحديده بالشريحة.

وهذا مثال لفهم الموضوع أكثر

package main

import (
"fmt"
)

func main() {
fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"}
fruitslice := fruitarray[1:3]
fmt.Printf("length of slice %d capacity %d", len(fruitslice), cap(fruitslice))
}

في المثال السابق, أنشئنا شريحة fruitslice تعتمد على العنصرين ذوي الفهارس (1 و 2) من المصفوفة fruitarray, بالتالي فإن طول الشريحة هو 2.
طول المصفوفة fruitarray هو 7, والشريحة fruitslice تم انشاؤها بدءاً من الفهرس رقم 1 للمصفوفة fruitarray (العنصر الثاني), أي من العنصر orange, بالتالي فإن مدى استيعاب الشريحة هو 6 (عدد عناصر المصفوفة الأصلية 7 – العنصر الاول تم تجاهله في الشريحة 1 = 6 عناصر).

  • انشاء شريحة باستخدام الدالة make

يمكننا من خلال الدالة make انشاء شريحة عبر تمرير نوع بياناتها وطولها ومدى استيعابها (مدى الاستيعاب اختياري), هذه الدالة تقوم بانشاء مصفوفة وتُعيد لنا شريحة مبنية عليها.

مثال

package main

import (
"fmt"
)

func main() {
i := make([]int, 5, 5)
fmt.Println(i)
}

والنتيجة ستكون

[0 0 0 0 0]
  • إضافة عناصر للشريحة

كما علمنا سابقاً من درس المصفوفات في لغة غو, أن للمصفوفات طول محدد ثابت لايمكن زيادته, أما الشرائح فهي ديناميكية ويمكننا إضافة عناصر لها عبر الدالة append ذات الصيغة التالية:

func append(s []T, x ...T) []T

حيث x …T تعني أن الدالة تقبل عدد غير محدد من الـ arguments للباراميتر x, وهذا النوع من الدوال سيتم شرحه في الدروس القادمة بتفصيل.

اذا كانت المصفوفات غير قابل لزيادة عناصرها, واذا كانت الشرائح مبنية على المصفوفات, فكيف يمكن زيادة عناصر للشرائح ؟؟!

الجواب: حسناً, هذا كله يحصل دون أن يُرى. فعلياً, عند إضافة عناصر للشريحة, يتم انشاء مصفوفة جديدة وعناصر المصفوفة الأولى يتم نسخها الى المصفوفة الجديدة (المخفية), ويتم إرجاع مرجع reference للشريحة المعتمدة على المصفوفة الجديدة المخفية.
ومدى استيعاب الشريحة الجديدة هو ضعف ماكان عليه, الامر معقد قليلاً وهذا مثال لتبسيط الامور ..

package main

import (
"fmt"
)

func main() {
cars := []string{"Ferrari", "Honda", "Ford"}
fmt.Println("cars:", cars, "has old length", len(cars), "and capacity", cap(cars))
cars = append(cars, "Toyota")
fmt.Println("cars:", cars, "has new length", len(cars), "and capacity", cap(cars))
}

في المثال السابق, مدى استيعاب الشريحة cars هو 3 مبدئياً, أضفنا للشريحة عنصر جديد في السطر العاشر, والان اصبح مدى استيعاب Capacity الشريحة هو 6
ونتيجة تنفيذ المثال ستكون

cars: [Ferrari Honda Ford] has old length 3 and capacity 3
cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6

والقيم الفارغة للشرائح هي من نوع nil, وسيتم شرح موضوع القيم الفارغة (القيم الصفرية) لكل نوع بيانات في دروس قادمة.

package main

import (
"fmt"
)

func main() {
//zero value of a slice is nil
var names []string
if names == nil {
fmt.Println("slice is nil going to append")
names = append(names, "John", "Sebastian", "Vinay")
fmt.Println("names contents:",names)
}
}

والنتيجة

slice is nil going to append
names contents: [John Sebastian Vinay]

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

مثال

package main

import (
"fmt"
)

func main() {
veggies := []string{"potatoes","tomatoes","brinjal"}
fruits := []string{"oranges","apples"}
food := append(veggies, fruits...)
fmt.Println("food:",food)
}

في السطر العاشر من المثال أعلاه, food تم إنشاؤها عبر إضافة fruits إلى veggies
ونتيجة تنفيذ المثال ستكون

food: [potatoes tomatoes brinjal oranges apples]
  • شرائح متعددة الأبعاد Multidimensional Slices

مثال

package main

import (
"fmt"
)

func main() {
pls := [][]string {
{"C", "C++"},
{"JavaScript"},
{"Go", "Rust"},
}
for _, v1 := range pls {
for _, v2 := range v1 {
fmt.Printf("%s ", v2)
}
fmt.Printf("\n")
}
}

والنتيجة

C C++
JavaScript
Go Rust
  • خلاصة المصفوفات Arrays والشرائح Slices

    في الرابط التالي على حسابنا في GitHub يوجد ملف شامل لكل ماتم شرحه بدرس المصفوفات ودرس الشرائح بأمثلة عملية, يمكنك استخدامه كمرجع..
    الرابط:
    https://github.com/argolang/arraysandslices

ملاحظة: يمكنك تشغيل أكواد وأمثلة لغة غو من خلال GoLang Playground أو GoPlay.Space .

نبذة عن الكاتب

Firas M. Darwish

Software Engineer, PHP/Laravel, C#, GoLang, founder of ArGoLang.com & others ..

شاركنا رأيك :)