في Go، تُكرّر for range كتلةً من الكود للقيم المستخرجة من تعبير range. ويحدّد تعبير range ما إذا كان كل تكرار سيُنتج قيمة واحدة أم قيمتين.
range
يُنتج range على مصفوفة فهرس كل عنصر وقيمته بالترتيب:
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(i, v)
}
// 0 10
// 1 20
// 2 30
يُنتج range على خريطة كل مفتاح وقيمته، لكن ترتيب التكرار غير مضمون. تُعشّئ Go ترتيب تكرار الخريطة عمدًا، لذا قد يُنتج البرنامج نفسه مخرجات مختلفة في كل تشغيل.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// 99 20
// 999 30
// 9 10
يُنتج range على سلسلة نصية فهرس البايت وكل rune (نقطة كود Unicode). في المثال التالي، تشغل 子 ثلاثة بايتات، لذا يبدأ 猫 عند فهرس البايت 3، وليس 1.
for i, r := range "子猫" {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 3 29483 猫
إذا احتجت إلى فهارس rune بدلًا من ذلك، فحوّل السلسلة النصية إلى مصفوفة من rune:
for i, r := range []rune("子猫") {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 1 29483 猫
يمكن لـ range أن يكرّر على عدد صحيح مباشرةً، فيُنتج قيمًا تبدأ من 0 وتصل إلى ذلك العدد الصحيح دون أن تشمله. الصفر والقيم السالبة صالحة لكنها لا تُنتج أي تكرار.
for n := range 3 {
fmt.Println(n)
}
// 0
// 1
// 2
يقبل range مكرِّرًا من النوع iter.Seq[V] أو iter.Seq2[K, V]. والمكرِّر دالة تُنتج تسلسلًا من القيم قيمةً تلو الأخرى. ثم يستطيع range أن يمرّ عبر تلك القيم.
text := "The quick brown fox"
for word := range strings.FieldsSeq(text) {
fmt.Println(word)
}
// The
// quick
// brown
// fox
names := []string{"Alice", "Bob", "Vera"}
for i, v := range slices.All(names) {
fmt.Println(i, ":", v)
}
// 0 : Alice
// 1 : Bob
// 2 : Vera
أخيرًا، يمكن لـ range أن يستقبل القيم المُرسَلة عبر قناة حتى تُغلق تلك القناة في مكان آخر. وتُغطّى القنوات بمزيد من التفصيل لاحقًا في منهج المسار.
لن يُصرَّف الكود في Go إذا أُعلن عن متغير ولم يُستخدم أبدًا.
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(v)
}
// Go build failed: declared and not used: i
إذا كنت تحتاج القيمة فقط، فأسند الفهرس أو المفتاح إلى _ لتتجاهله.
vals := []int{10, 20, 30}
for _, v := range vals {
fmt.Println(v)
}
// 10
// 20
// 30
إذا كنت تحتاج الفهرس فقط، فاحذفه تمامًا:
vals := []int{10, 20, 30}
for i := range vals {
fmt.Println(i)
}
// 0
// 1
// 2
إذا لم تكن بحاجة إلى الفهرس ولا إلى القيمة، فيمكن حذفهما معًا:
vals := []int{10, 20, 30}
count := 0
for range vals {
count++
}
// count == 3