1.9 حلقه‌ها (for)

1.9 حلقه‌ها (for)

1.9.1 حلقه #

حلقه‌ها را در زبان گو به ساده‌ترین شکل ممکن و فقط با استفاده از کلید واژه for و در مدل‌های مختلف (سه‌بخشی، بی نهایت، foreach و …) می‌توان پیاده‌سازی کرد.

1.9.2 حلقه سه بخشی #

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

  • مقداردهی
  • شرط
  • شمارنده

ایجاد می‌شوند.

for initialization ; condition ; counter {
	//loop codes
}

در مثال زیر نمونه‌ای از این حلقه‌ قابل مشاهده و اجرا است.

package main

import "fmt"

func main() {
	sum := 0
	for i := 1; i < 10; i++ {
		sum += i
	}

	fmt.Println(sum)
}

1.9.3 حلقه while #

این مدل حلقه شبیه while در بیشتر زبان ها مثل پایتون و C است. با این تفاوت که پیاده‌سازی آن، تنها با کلیدواژه‌ی for و با حذف بخش مقداردهی و شمارنده حلقه سه‌بخشی انجام می‌گیرد. در واقع در این حلقه تنها یک شرط تعریف می‌شود و تا برقرار بودن آن شرط حلقه اجرا می‌شود. به مثال زیر توجه کنید:

package main

import "fmt"

func main() {
	i := 0
	for i < 10 {
		fmt.Println(i)
		i++
	}
}

1.9.4 حلقه بی‌نهایت #

اگر از حلقه‌ی while که در مثال بالا تعریف کردیم بخش شرط را حذف کنیم چه اتفاقی می‌افتد؟ در این حالت ما یک شرط بی نهایت ساخته‌ایم (شبیه به while(1)) که تا زمانی‌ که برنامه متوقف نشود و یا کدهای داخل حلقه، فرمان خروج از حلقه را ندهند، چرخه ی اجرای حلقه ادامه خواهد یافت.

package main

import "fmt"

func main() {
	sum := 0
	for {
		sum++
	}

	fmt.Println("this line will never execute")
}

با اجرای کد بالا خطای تایم‌اوت دریافت خواهید کرد (اگر در playground سایت گو اجراش کنین)، به‌ دلیل اینکه حلقه هیچ‌گاه تمام نمی‌شود.

1.9.5 حلقه for-range #

حلقه for-range یکی از پرکاربردترین حلقه‌ها در زبان گو می‌باشد که شما می‌توانید برای slice، آرایه و map یا رشته از این حلقه استفاده کنید.

for index, value := range slice/array {}
for key, value := range map {}

1.9.5.1 حلقه for-range برای slice و آرایه #

شما با استفاده از حلقه for-range می‌توانید به المنت‌های آرایه یا slice و همچنین اندیس‌شان (Index) دسترسی پیدا کنید. دقت کنید ۲ حالت وجود دارد:

1.9.5.1.1 دسترسی با استفاده از یک کپی از المنت #

در کد زیر ما با استفاده از for-range به یک کپی از المنت‌های اسلایس letter دسترسی پیدا کردیم.

package main

import "fmt"

func main() {
    letters := []string{"a", "b", "c"}

    //With index and value
    fmt.Println("Both Index and Value")
    for i, letter := range letters {
        fmt.Printf("Index: %d Value:%s\n", i, letter)
    }

	//Only value
    fmt.Println("\nOnly value")
    for _, letter := range letters {
        fmt.Printf("Value: %s\n", letter)
    }
}

1.9.5.1.2 دسترسی مستقیم به خانه حافظه المنت #

شما با استفاده از اندیس (index) می‌توانید مستقیماً به خانه حافظه المنت دسترسی پیدا کنید و آن المنت رو با استفاده از اندیس (Index) نمایش بدید. به مثال زیر توجه کنید:

package main

import "fmt"

func main() {
    letters := []string{"a", "b", "c"}

    fmt.Println("\nOnly letter")
    for i := range letters {
        fmt.Printf("letter: %s\n", letters[i])
    }
}

1.9.1.2 حلقه for-range برای map #

شما با استفاده از حلقه for-range برروی map, میتوانید به کلید و مقدار هر یک از مقادیر map دسترسی پیدا کنید.

package main

import "fmt"

func main() {
    sample := map[string]string{
        "a": "x",
        "b": "y",
    }

    //Iterating over all keys and values
    fmt.Println("Both Key and Value")
    for k, v := range sample {
        fmt.Printf("key :%s value: %s\n", k, v)
    }

    //Iterating over only keys
    fmt.Println("\nOnly keys")
    for k := range sample {
        fmt.Printf("key :%s\n", k)
    }

    //Iterating over only values
    fmt.Println("\nOnly values")
    for _, v := range sample {
        fmt.Printf("value :%s\n", v)
    }
}

1.9.1.3 حلقه for-range برای رشته (string) #

شما با استفاده از حلقه for-range می توانید به هرکدام از کارکترهای رشته دسترسی پیدا کنید.

for index, character := range string {
    //Do something with index and character
}

به کد نمونه زیر توجه کنید :

package main

import "fmt"

func main() {
    sample := "a£b"

    //With index and value
    fmt.Println("Both Index and Value")
    for i, letter := range sample {
        fmt.Printf("Start Index: %d Value:%s\n", i, string(letter))
    }

    //Only value
    fmt.Println("\nOnly value")
    for _, letter := range sample {
        fmt.Printf("Value:%s\n", string(letter))
    }

    //Only index
    fmt.Println("\nOnly Index")
    for i := range sample {
        fmt.Printf("Start Index: %d\n", i)
    }
}

1.9.6 کلید واژه break #

با استفاده از break می‌توان چرخه‌ی اجرای یک حلقه را پایان داد. به عنوان مثال در حلقه بی‌نهایتی که در بخش 1.9.4 مشاهده کردید، می‌توان با تعریف یک شرط خاص از حلقه خارج شد. کد زیر نمونه استفاده از break را نمایش می‌دهد.

package main

import "fmt"

func main() {
	sum := 0
	for {
		sum++
		if sum == 10 {
			break
		}
	}

	fmt.Println(sum)
	fmt.Println("now this line will execute")
}

1.9.7 label در حلقه ها #

شما با قابلیت label در زبان گو می‌توانید لیبلی را به یک حلقه خاص اختصاص دهید و بعد از چند حلقه تو در تو حلقه مورد نظر را break کنید.

package main

import "fmt"

func main() {
    letters := []string{"a", "b", "c"}

	for i := 1; i < 10; i++ {
        // define a lable with name 'second' for this loop
        second:
            for i := 2; i < 9; i++ {
                for _, l := range letters {
                    if l == "b" {
                        // break the loop with second lable
                        break second
                    }
                }
            }
	}
}

در کد بالا زمانی که از لیبل استفاده نشود سومین حلقه درونی break خواهد شد. اما با استفاده از لیبل‌ها هرکدام از حلقه‌های مورد نظر را می‌توان break کرد.

1.9.8 کلیدواژه continue #

این کلید‌واژه چرخه‌ اجرای حلقه را یک مرحله جلو می‌برد. به این‌ معنی که اگر در حلقه از این کلید‌واژه استفاده شود، کدهای بعد از continue اجرا نشده و چرخه بعدی (گام بعدی) اجرا خواهد شد.

package main

import "fmt"

func main() {

	for i := 1; i < 10; i++ {
		if i%2 == 0 {
			continue
		}
		fmt.Println(i)
	}
}
قابل ذکر است که continue و break در حلقه‌های تو در تو، فقط روی اولین حلقه درونی تاثیر خواهند گذاشت.

1.9.9 خودآزمون حلقه #

با استفاده از زبان گو برنامه‌ای بنویسید که سری‌ زیر را ایجاد کند:

1
22
333
55555
88888888
13131313131313131313131313
212121212121212121212121212121212121212121
  • ‍1 + 0 = 1
  • 1 + 1 = 2
  • 2 + 1 = 3
  • 3 + 2 = 5
  • 5 + 3 = 8
  • 8 + 5 = 13
  • 13 + 8 = 21

  • a + b = c
  • b = a
  • a = c

package main

import "fmt"

func main() {
   var (
      n       = 6  // can define any result count ...
      a, b, c = 1, 0, 0
   )
   for i := 0; i <= n; i++ {
      c = a + b
      for j := 1; j <= c; j++ {
         fmt.Print(c)
      }
      fmt.Println()
      b, a = a, c
   }
}