در Go میتوانید با استفاده از for و یک اندیس، روی یک slice پیمایش کنید، یا میتوانید از 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 را پیادهسازی کنید.
باید با پیمایش روی رتبهی دادهشده، تعداد کل خانههای اشغالشده را بشمارد.
یک عدد صحیح برگردانید.
اگر رتبهی دادهشده معتبر نباشد (یعنی بین 1 و 8 با احتساب خودشان نباشد)، شمارش صفر (0) را برگردانید.
CountInRank(board, 2)
// => 1
تابع CountAll(board Chessboard) int را پیادهسازی کنید.
باید بشمارد چند خانه در صفحهی شطرنج وجود دارد و یک عدد صحیح برگرداند.
از آنجا که نیازی نیست محتوای خانهها را بررسی کنید، استفاده از range را با حذف هم index و هم value در نظر بگیرید.
CountAll(board)
// => 64
تابع CountOccupied(board Chessboard) int را پیادهسازی کنید.
باید بشمارد چند خانه در صفحهی شطرنج اشغال شده است.
یک عدد صحیح برگردانید.
CountOccupied(board)
// => 15