في Go، يمكنك التكرار على slice باستخدام for وفهرس، أو يمكنك استخدام range. كما يسمح لك range بالتكرار على map.
كل تكرار يُرجع قيمتين: الفهرس/المفتاح ونسخةً من العنصر عند ذلك الفهرس/المفتاح.
slice
سهل للغاية، فالحلقات على slice مرتّبة كما هو متوقع.
xi := []int{10, 20, 30}
for i, x := range xi {
fmt.Println(i, x)
}
// outputs:
// 0, 10
// 1, 20
// 2, 30
map
التكرار على map يطرح مشكلة جديدة.
فالترتيب الآن عشوائي.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// outputs, for example:
// 99 20
// 999 30
// 9 10
قد يبدو المخرَج أعلاه غير صحيح، إذ يتوقع المرء أن يكون أول زوج مفتاح/قيمة عند تعريف map، أي 9 10، هو أول ما يُطبع لا آخره.
لكن map غير مرتّبة بطبيعتها، فليس فيها زوج مفتاح/قيمة أول أو أخير.
ولهذا السبب، عند التكرار على مدخلات map، يكون الترتيب الذي ستُزار به المدخلات عشوائيًا ولا يتبع أي نمط محدّد.
هذا يعني أن المخرَج أعلاه ممكن، لكنه قد يختلف عمّا ستحصل عليه إذا جرّبت تشغيل هذا بنفسك.
لمعرفة المزيد عن هذا، راجع مواصفات لغة Go: جملة range.
في Go، المتغير غير المستخدم يؤدي إلى خطأ في وقت البناء. أحيانًا تحتاج إلى القيمة فقط، كما في المثال الأول:
xi := []int{10, 20, 30}
for i, x := range xi {
fmt.Println(x)
}
// Go build failed: i declared but not used
يمكنك استبدال i بـ _، وهذا يخبر المترجم بأننا لا نستخدم تلك القيمة:
xi := []int{10, 20, 30}
for _, x := range xi {
fmt.Println(x)
}
// outputs:
// 10
// 20
// 30
إذا أردت طباعة الفهرس فقط، يمكنك استبدال x بـ _،
أو ببساطة حذف التعريف:
xi := []int{10, 20, 30}
// for i, _ := range xi {
for i := range xi {
fmt.Println(i)
}
// outputs:
// 0
// 1
// 2
يُنشئ تعريف النوع نوعًا جديدًا مُسمّى، متميّزًا عن كل نوع آخر، حتى لو كان له النوع الأساسي نفسه.
type File []bool
يشير File هنا إلى عمود رأسي واحد على رقعة الشطرنج، يُرمز إليه عادةً بالحروف من A إلى H.
وتُمثَّل كل خانة في هذا العمود بقيمة منطقية تحدّد ما إذا كانت مشغولة أم لا.
وبعد أن صار File معرَّفًا، يمكننا استخدامه داخل تعريفات أخرى:
type Chessboard map[string]File
board := Chessboard{
"A": File{true, false, true},
"B": File{false, true, false},
}
يربط Chessboard معرّفات الأعمدة بقيم File.
وكل File عبارة عن slice من القيم المنطقية تُمثّل خانات عمود واحد على رقعة الشطرنج.
وبدون تعريفات الأنواع هذه، سيكون board من نوع map[string][]bool، وهذا يجعل فهم ما نمثّله أصعب.
بصفتك من محبّي الشطرنج، تودّ كتابة نسختك الخاصة من اللعبة. صحيح أن هناك الكثير من تطبيقات الشطرنج المتاحة على الإنترنت بالفعل، لكن نسختك ستكون فريدة!
يُحدَّد كل مربع من مربعات رقعة الشطرنج بزوج من حرف ورقم:
A B C D E F G H
8 # _ _ _ # _ _ # 8
7 _ _ _ _ _ _ _ _ 7
6 _ _ _ _ # _ _ # 6
5 _ # _ _ _ _ _ # 5
4 _ _ _ _ _ _ # # 4
3 # _ # _ _ _ _ # 3
2 _ _ _ _ _ _ _ # 2
1 # _ _ _ _ _ _ # 1
A B C D E F G H
نفّذ الدالة CountInFile(board Chessboard, file string) int.
ينبغي أن تحسب العدد الإجمالي للمربعات المشغولة بالمرور على خريطة.
أرجِع عددًا صحيحًا.
أرجِع صفرًا (0) إذا لم يُعثر على الملف المعطى في الخريطة.
CountInFile(board, "A")
// => 3
نفّذ الدالة CountInRank(board Chessboard, rank int) int.
ينبغي أن تحسب العدد الإجمالي للمربعات المشغولة بالمرور على الرتبة المعطاة.
أرجِع عددًا صحيحًا.
أرجِع صفرًا (0) إذا لم تكن الرتبة المعطاة صالحة (ليست بين 1 و8 ضمنا).
CountInRank(board, 2)
// => 1
نفّذ الدالة CountAll(board Chessboard) int.
ينبغي أن تحسب عدد المربعات الموجودة في رقعة الشطرنج وتُرجع عددًا صحيحًا.
بما أنك لست بحاجة إلى فحص محتوى المربعات، فكّر في استخدام range مع حذف كلٍّ من index وvalue.
CountAll(board)
// => 64
نفّذ الدالة CountOccupied(board Chessboard) int.
ينبغي أن تحسب عدد المربعات المشغولة في رقعة الشطرنج.
أرجِع عددًا صحيحًا.
CountOccupied(board)
// => 15
سجّل في Exercism لتتعلّم وتتقن Go عبر 34 مفهومًا166 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.