حلقه ها | گولنگ به زبان ساده

تاریخ انتشار:
حلقه ها | گولنگ به زبان ساده
با حقله ها آشنا میشیم و یاد میگیریم چطور به کمک حلقه ها می‌توان مجموعه‌ای از دستورات را تکرار کرد.

با استفاده از حلقه ها میتوان مجموعه ای از دستورات را به صورت تکراری اجرا کرد.  تنها یک نوع حلقه وجود دارد که همان حلقه for است. با این حال، این حلقه می‌تواند به روش‌های مختلفی استفاده شود.

حلقه شمارشی

حلقه شمارشی دارای سه بخش است:

  • مقداردهی اولیه (initialization): دراین بخش متغیری تعریف و مقداردهی می‌شود. این بخش فقط یک بار در ابتدای حلقه اجرا می‌شود.
  • شرط (condition): شرط حلقه قبل از هر تکرار بررسی می‌شود. اگر شرط درست (true) باشد، بدنه حلقه اجرا می‌شود؛ در غیر این صورت، حلقه متوقف می‌شود.
  • بروز رسانی (post): پس از هر بار اجرای دستورات داخل حلقه، این بخش اجرا می‌شود تا متغیر شمارنده به‌روزرسانی شود.
for initialization; condition; post {
    // دستورات داخل حلقه
}

برای مثال کد زیر اعداد از ۱ تا ۵۰ را نمایش میدهد:

package main

import "fmt"

func main() {
	for i := 1; i <= 50; i++ {
		fmt.Println(i)
	}
}

هرکدام از بخش های حلقه ی شمارشی را میتوان بر حسب شرایط حذف کرد و یا به بیرون یا داخل حلقه انتقال داد:

package main

import "fmt"

func main() {
	i := 1

	for i <= 50 {
		fmt.Println(i)
		i++
	}
}

حلقه بی نهایت

چنانچه شرط حلقه را حذف کنیم, حلقه بی نهایت ایجاد میشود. کد زیر به صورت بی نهایت اجرا میشود و در هر ثانیه زمان کنونی رو در صفحه چاپ میکند:

package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println(time.Now())
		time.Sleep(1 * time.Second)
	}
}

چنانچه در برنامه خود حلقه‌ی بی نهایتی داشته باشید که از منابع سیستم (cpu, ram, gpu) خیلی استفاده کند, ممکن است برنامه شما با خطای کمبود منابع مواجهه شود.

حلقه روی مجموعه ها

ایجاد حلقه روی مجموعه‌ها به کمک ساختار for range انجام می‌شود که به ما این امکان را می‌دهد تا روی انواع مجموعه‌ها مانند آرایه‌ها، مپ‌ها، اسلایس‌ها، رشته‌ها (strings) و چنل‌ها (channels) پیمایش کنیم. این حلقه برای دسترسی به هر عنصر از مجموعه استفاده می‌شود.

ساختار کلی این حلقه به صورت زیر است:

for index, value := range collection {
    // دستورات داخل حلقه
}
  • index: اندیسِ عنصرِ فعلی
  • value: مقدارِ عنصرِ فعلی
  • collection: مجموعه‌ای که روی آن پیمایش انجام میشود
package main

import "fmt"

func main() {
	names := []string{
		"John Doe",
		"Alex Newman",
		"Mahdi Khanzadi",
	}

	for i, name := range names {
		fmt.Printf("index is: %d and value is: %q\n", i, name)
	}
}

// خروجی حاصل از اجرای کد بالا :
// index is: 0 and value is: "John Doe"
// index is: 1 and value is: "Alex Newman"
// index is: 2 and value is: "Mahdi Khanzadi"

در صورتی که تنها به مقدارِ هر عنصر نیاز دارید میتوانید بجای اندیس _ را قرار  دهید.

package main

import "fmt"

func main() {
	names := []string{
		"John Doe",
		"Alex Newman",
		"Mahdi Khanzadi",
	}

	for _, name := range names {
		fmt.Printf("value is: %q\n", name)
	}
}

// خروجی حاصل از اجرای کد بالا :
// value is: "John Doe"
// value is: "Alex Newman"
// value is: "Mahdi Khanzadi"

در صورتی که تنها به اندیسِ هر عنصر نیاز دارید میتوانید به صورت زیر عمل کنید:

package main

import "fmt"

func main() {
	names := []string{
		"John Doe",
		"Alex Newman",
		"Mahdi Khanzadi",
	}

	for i := range names {
		fmt.Printf("index is: %d and value is: %q\n", i, names[i])
	}
}

// خروجی حاصل از اجرای کد بالا :
// index is: 0 and value is: "John Doe"
// index is: 1 and value is: "Alex Newman"
// index is: 2 and value is: "Mahdi Khanzadi"

دستور break , continue و label

با اجرای دستور break میتوان از حلقه ی فعلی خارج شد. برای مثال حلقه زیر اعداد ۰ تا ۱۰ را نمایش میدهد و با اجرای break از حلقه خارج می‌شود.

package main

import "fmt"

func main() {
	var i int

	for {
		if i > 10 {
			break
		}

		fmt.Println(i)

		i += 2
	}
}

دستور continue باعث میشود کدهای بعد از continue اجرا نشود و حلقه به گام بعدی برود. در حلقه زیر با اجرای دستور continue مانع نمایش اعداد فرد می شویم و اعداد ۰ تا ۱۰ را نمایش می‌دهیم:

package main

import "fmt"

func main() {
	for i := 0; i <= 10; i++ {
		if i%2 != 0 {
			continue
		}

		fmt.Println(i)
	}
}

با استفاده از label میتوان خطی از کد را نشانه گذاری کرد و سپس با استفاده از دستورات break یا continue از داخلی ترین حلقه به جایی که label بیرونی است پرید:

package main

import "fmt"

func main() {

loop:
	for i := 0; i < 5; i++ {
		for j := 0; j < 5; j++ {
			if i == 2 {
				break loop
			}
			fmt.Printf("i: %d, j: %d\n", i, j)
		}
	}
}

// نتیجه خروجی:
// i: 0, j: 0
// i: 0, j: 1
// i: 0, j: 2
// i: 0, j: 3
// i: 0, j: 4
// i: 1, j: 0
// i: 1, j: 1
// i: 1, j: 2
// i: 1, j: 3
// i: 1, j: 4

در کد بالا وقتی break رو کال میکنیم از داخلی ترین حلقه به جایی که loop نامگذاری کردیم میپریم و چون دستور break رو استفاده کردیم, اجرای تمام حلقه هایی که توی این مسیر هستند خاتمه پیدا می کنند.

در مثال زیر از continue استفاده میکنیم و یک گام هردو حلقه را به جلو می‌پریم:

package main

import "fmt"

func main() {

loop:
	for i := 0; i < 5; i++ {
		for j := 0; j < 5; j++ {
			if i == 2 {
				continue loop
			}
			fmt.Printf("i: %d, j: %d\n", i, j)
		}
	}	
}

// نتیجه خروجی:
// i: 0, j: 0
// i: 0, j: 1
// i: 0, j: 2
// i: 0, j: 3
// i: 0, j: 4
// i: 1, j: 0
// i: 1, j: 1
// i: 1, j: 2
// i: 1, j: 3
// i: 1, j: 4
// i: 3, j: 0
// i: 3, j: 1
// i: 3, j: 2
// i: 3, j: 3
// i: 3, j: 4
// i: 4, j: 0
// i: 4, j: 1
// i: 4, j: 2
// i: 4, j: 3
// i: 4, j: 4

جمع بندی

از حلقه ها برای تکرار دستورات استفاده می‌شود. در گولنگ تنها یک حلقه for داریم اما به چندین روش متفاوت میتوان از این حلقه استفاده کرد.


قسمت قبل: نوع داده slice | گولنگ به زبان ساده

قسمت بعد: نوع داده map | گولنگ به زبان ساده