1.9 حلقه‌ها (for)

1.9 حلقه‌ها (for)

1.9.1 حلقه #

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

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

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

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

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

1for initialization ; condition ; counter { 
2	//loop codes 
3} 

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	sum := 0
 7	for i := 1; i < 10; i++ {
 8		sum += i
 9	}
10
11	fmt.Println(sum)
12}
1$ go run main.go
245

1.9.3 حلقه while #

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	i := 0
 7	for i < 10 {
 8		fmt.Println(i)
 9		i++
10	}
11}
 1$ go run main.go
 20
 31
 42
 53
 64
 75
 86
 97
108
119

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

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	sum := 0
 7	for {
 8		sum++
 9	}
10
11	fmt.Println("this line will never execute")
12}

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

1.9.5 حلقه for-range #

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

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

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

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

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

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6    letters := []string{"a", "b", "c"}
 7
 8    //With index and value
 9    fmt.Println("Both Index and Value")
10    for i, letter := range letters {
11        fmt.Printf("Index: %d Value:%s\n", i, letter)
12    }
13    
14	//Only value
15    fmt.Println("\nOnly value")
16    for _, letter := range letters {
17        fmt.Printf("Value: %s\n", letter)
18    }
19}
 1$ go run main.go
 2Both Index and Value
 3Index: 0 Value:a
 4Index: 1 Value:b
 5Index: 2 Value:c
 6
 7Only value
 8Value: a
 9Value: b
10Value: c

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

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6    letters := []string{"a", "b", "c"}
 7
 8    fmt.Println("\nOnly letter")
 9    for i := range letters {
10        fmt.Printf("letter: %s\n", letters[i])
11    }
12}
1$go run main.go
2Only letter
3letter: a
4letter: b
5letter: c

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

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6    sample := map[string]string{
 7        "a": "x",
 8        "b": "y",
 9    }
10
11    //Iterating over all keys and values
12    fmt.Println("Both Key and Value")
13    for k, v := range sample {
14        fmt.Printf("key :%s value: %s\n", k, v)
15    }
16
17    //Iterating over only keys
18    fmt.Println("\nOnly keys")
19    for k := range sample {
20        fmt.Printf("key :%s\n", k)
21    }
22
23    //Iterating over only values
24    fmt.Println("\nOnly values")
25    for _, v := range sample {
26        fmt.Printf("value :%s\n", v)
27    }
28}
 1$go run main.go
 2Both Key and Value
 3key :a value: x
 4key :b value: y
 5
 6Only keys
 7key :a
 8key :b
 9
10Only values
11value :x
12value :y

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

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

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

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6    sample := "a£b"
 7
 8    //With index and value
 9    fmt.Println("Both Index and Value")
10    for i, letter := range sample {
11        fmt.Printf("Start Index: %d Value:%s\n", i, string(letter))
12    }
13
14    //Only value
15    fmt.Println("\nOnly value")
16    for _, letter := range sample {
17        fmt.Printf("Value:%s\n", string(letter))
18    }
19
20    //Only index
21    fmt.Println("\nOnly Index")
22    for i := range sample {
23        fmt.Printf("Start Index: %d\n", i)
24    }
25}
 1$ go run main.go
 2Both Index and Value
 3Start Index: 0 Value:a
 4Start Index: 1 Value:£
 5Start Index: 3 Value:b
 6
 7Only value
 8Value:a
 9Value:£
10Value:b
11
12Only Index
13Start Index: 0
14Start Index: 1
15Start Index: 3

1.9.6 کلید واژه break #

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6	sum := 0
 7	for {
 8		sum++
 9		if sum == 10 {
10			break
11		}
12	}
13
14	fmt.Println(sum)
15	fmt.Println("now this line will execute")
16}
1$ go run main.go
210
3now this line will execute

1.9.7 label در حلقه ها #

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6    letters := []string{"a", "b", "c"}
 7
 8	for i := 1; i < 10; i++ {
 9        // define a lable with name 'second' for this loop
10        second:
11            for i := 2; i < 9; i++ {
12                for _, l := range letters {
13                    if l == "b" {
14                        // break the loop with second lable
15                        break second
16                    }
17                }
18            }
19	}
20}

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

1.9.8 کلیدواژه continue #

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

 1package main
 2
 3import "fmt"
 4
 5func main() {
 6
 7	for i := 1; i < 10; i++ {
 8		if i%2 == 0 {
 9			continue
10		}
11		fmt.Println(i)
12	}
13}
1$ go run main.go
21
33
45
57
69
قابل ذکر است که continue و break در حلقه‌های تو در تو، فقط روی اولین حلقه درونی تاثیر خواهند گذاشت.

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

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

11
222
3333
455555
588888888
613131313131313131313131313
7212121212121212121212121212121212121212121
  • ‍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

 1package main  
 2  
 3import "fmt"  
 4  
 5func main() {  
 6   var (  
 7      n       = 6  // can define any result count ...  
 8      a, b, c = 1, 0, 0  
 9   )  
10   for i := 0; i <= n; i++ {  
11      c = a + b  
12      for j := 1; j <= c; j++ {  
13         fmt.Print(c)  
14      }  
15      fmt.Println()  
16      b, a = a, c  
17   }  
18}