# Loops

Course: [Go](https://www.devtutorials.ai/learn/go) · Section: Control Flow
Source: https://www.devtutorials.ai/learn/go/control-flow/loops

> Repeat work in Go with the for loop in its three forms, walk through arrays, slices, strings, maps and channels with range, and control loops with break, continue, labels and goto.

## What Are Loops?

**Loop** = code that repeats while a condition is true.

**Iteration** = one trip through the loop.

Without a loop, printing roll numbers 1 to 40 needs 40 lines.
With a loop, it needs 3.

**Simple lesson:** a loop repeats work so you do not have to write the same line again and again.

### A Real-World Example

At morning assembly, the teacher takes attendance.

- She starts at roll number 1.
- She calls one name and marks it.
- She moves to the next roll number.
- She stops after the last student.

That is a loop:

- **Start** at 1.
- **Check** if there are students left.
- **Do** the work: call the name.
- **Move** to the next number.

Go has only **one** loop keyword: `for`.

- It can count, like a `for` loop in other languages.
- It can wait for a condition, like a `while` loop.
- It can run forever.
- With `range`, it can walk through lists, text, maps and channels.

## What You Will Learn

In this lesson, you will learn:

1. Why loops are used.
2. The three forms of `for`: counting, condition-only and infinite.
3. How `range` walks through arrays, slices, strings, maps and channels.
4. How to stop or skip with `break` and `continue`, and how labels work.
5. How to put one loop inside another.

## Loop Fundamentals

### Why Loops Are Used

- **Repeat a task** a fixed number of times, like printing a table.
- **Go through every item** in a list, like all students' marks.
- **Keep trying** until something happens, like a correct password.
- **Add things up**, like a total or a count.

```go runnable title="Without and with a loop"
package main

import "fmt"

func main() {
	fmt.Println("Roll 1")
	fmt.Println("Roll 2")
	fmt.Println("Roll 3")

	for roll := 1; roll <= 3; roll++ {
		fmt.Println("Roll", roll)
	}
}
```

```text
Roll 1
Roll 2
Roll 3
Roll 1
Roll 2
Roll 3
```

- Both halves print the same thing.
- Change `3` to `40` in the loop, and it prints 40 lines. The first half would need 37 more lines.

**Simple lesson:** use a loop when the same work repeats.

## The for Loop

### Traditional for Loop

```go
for init; condition; post {
	// body
}
```

- **init** runs once, before the first trip.
- **condition** is checked before every trip. The loop stops when it is false.
- **post** runs after every trip, usually `i++`.
- **body** is the work to repeat.

Move the slider, then step through the loop.

Watch the order:

- **init** happens once.
- Then it is always **check, body, post**, again and again.
- The last check is false, and the loop ends.

```go runnable title="The 7 times table"
package main

import "fmt"

func main() {
	for i := 1; i <= 5; i++ {
		fmt.Println("7 x", i, "=", 7*i)
	}
}
```

```text
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
```

- `i` lives only inside the loop.
- You can count down too: `for i := 10; i >= 1; i--`.

### Condition-Only Loop

Leave out init and post. Only the condition stays.

This is Go's version of a `while` loop.

- Use this form when you do not know how many trips you need.
- Something inside the loop must change the condition, or it never stops.

### Infinite Loop

**Infinite loop** = `for { }`, a loop with no condition. It runs until something stops it.

```go runnable title="An infinite loop with a way out"
package main

import "fmt"

func main() {
	guesses := []int{3, 8, 7}
	secret := 7
	tries := 0
	for {
		guess := guesses[tries]
		tries++
		if guess == secret {
			fmt.Println("Found it in", tries, "tries")
			break
		}
		fmt.Println(guess, "is wrong")
	}
}
```

```text
3 is wrong
8 is wrong
Found it in 3 tries
```

- `break` jumps out of the loop.
- Servers often run an infinite loop, waiting for requests.
- `[]int{3, 8, 7}` is a list of numbers called a **slice**. You will learn it in **Slices**.

A loop whose condition never becomes false runs forever.

In this lab, a program that runs too long is stopped after a few seconds. On your computer, press `Ctrl + C` in the terminal to stop it.

**Simple lesson:** `for` can count (init; condition; post), wait (condition only) or run forever (`for { }`).

## The range Loop

**range** = walk through every item in a collection, one at a time.

Each trip gives you the **index** (position) and the **value**.

### range with Arrays

```go runnable title="range over an array"
package main

import "fmt"

func main() {
	days := [3]string{"Mon", "Tue", "Wed"}
	for i, day := range days {
		fmt.Println(i, day)
	}
}
```

```text
0 Mon
1 Tue
2 Wed
```

- Positions start at `0`, not `1`.
- You will learn arrays in **Arrays**.

### range with Slices

```go runnable title="Total and average of marks"
package main

import "fmt"

func main() {
	marks := []int{91, 78, 85, 66}
	total := 0
	for _, m := range marks {
		total += m
	}
	fmt.Println("Total:", total)
	fmt.Println("Average:", float64(total)/float64(len(marks)))
}
```

```text
Total: 320
Average: 80
```

- `_` throws away the index, because we only need the marks.
- Write `for i := range marks` if you need only the index.

### range with Strings

```go runnable title="range over a string"
package main

import "fmt"

func main() {
	for i, r := range "Hi!" {
		fmt.Println(i, string(r))
	}
}
```

```text
0 H
1 i
2 !
```

- Each `r` is a **rune**: one character.
- For Hindi or emoji, `i` jumps by more than 1, because those characters use several bytes. See **Strings**.

### range with Maps

**Map** = a set of key and value pairs, like a phone book. You will learn it in **Maps**.

```go runnable title="Add up a map's values"
package main

import "fmt"

func main() {
	books := map[string]int{"Asha": 3, "Ravi": 5, "Meena": 2}
	total := 0
	for _, count := range books {
		total += count
	}
	fmt.Println("Books borrowed:", total)
}
```

```text
Books borrowed: 10
```

- Go walks through a map in a **different order each time**.
- So do not rely on the order when you print a map in a loop.
- Adding up gives the same answer in any order.

### range with Channels

**Channel** = a pipe that one part of a program uses to send values to another. You will learn it in **Channels**.

```go runnable title="range over a channel"
package main

import "fmt"

func main() {
	queue := make(chan string, 3)
	queue <- "Asha"
	queue <- "Ravi"
	close(queue)
	for name := range queue {
		fmt.Println("Next:", name)
	}
}
```

```text
Next: Asha
Next: Ravi
```

- `range` over a channel takes values until the channel is closed.

**Simple lesson:** `range` walks through each item and gives you its position and value.

## Loop Control Statements

### break

**break** = leave the loop right now.

```go runnable title="Stop at the first failing mark"
package main

import "fmt"

func main() {
	marks := []int{78, 92, 31, 88}
	for i, m := range marks {
		if m < 35 {
			fmt.Println("First fail at position", i)
			break
		}
		fmt.Println("OK:", m)
	}
}
```

```text
OK: 78
OK: 92
First fail at position 2
```

### continue

**continue** = skip the rest of this trip and start the next one.

```go runnable title="Print only the even roll numbers"
package main

import "fmt"

func main() {
	for roll := 1; roll <= 6; roll++ {
		if roll%2 != 0 {
			continue
		}
		fmt.Println("Roll", roll)
	}
}
```

```text
Roll 2
Roll 4
Roll 6
```

- For odd numbers, `continue` skips the print.
- The post statement `roll++` still runs.

### Labels

**Label** = a name for a loop, so `break` or `continue` can reach an **outer** loop.

```go runnable title="break out of two loops at once"
package main

import "fmt"

func main() {
	classes := [][]string{{"Asha", "Ravi"}, {"Meena", "Kabir"}}
	target := "Meena"
search:
	for c, class := range classes {
		for _, name := range class {
			if name == target {
				fmt.Println("Found", name, "in class", c)
				break search
			}
		}
	}
	fmt.Println("Search done")
}
```

```text
Found Meena in class 1
Search done
```

- `search:` names the outer loop.
- A plain `break` would leave only the inner loop.
- `break search` leaves both.

### goto

**goto** = jump to a label somewhere else in the same function.

```go runnable title="goto (rarely used)"
package main

import "fmt"

func main() {
	n := 1
again:
	fmt.Println("Try", n)
	n++
	if n <= 3 {
		goto again
	}
}
```

```text
Try 1
Try 2
Try 3
```

- `goto` exists, but it makes code hard to follow.
- Almost always, a `for` loop is clearer. Prefer it.

**Easy way to remember**

- `break` = leave the loop.
- `continue` = skip to the next trip.
- `break label` = leave an outer loop.
- `goto` = avoid it.

**Simple lesson:** `break` stops the loop, `continue` skips one trip, and labels let you reach an outer loop.

## Nested Loops

**Nested loop** = a loop inside another loop.

For every trip of the outer loop, the inner loop runs **all** its trips.

### Practical Examples

```go runnable title="A star triangle"
package main

import "fmt"

func main() {
	for row := 1; row <= 4; row++ {
		for star := 1; star <= row; star++ {
			fmt.Print("*")
		}
		fmt.Println()
	}
}
```

```text
*
**
***
****
```

- Row 1 prints 1 star, row 2 prints 2 stars, and so on.
- The inner loop uses the outer loop's `row` as its limit.

```go runnable title="Class toppers"
package main

import "fmt"

func main() {
	names := []string{"8A", "8B"}
	marks := [][]int{{78, 95, 88}, {91, 67, 84}}
	for c, list := range marks {
		best := 0
		for _, m := range list {
			if m > best {
				best = m
			}
		}
		fmt.Println(names[c], "top mark:", best)
	}
}
```

```text
8A top mark: 95
8B top mark: 91
```

- The outer loop picks a class.
- The inner loop finds the biggest mark in that class.

**Simple lesson:** in a nested loop, the inner loop finishes all its trips for each trip of the outer loop.

## TL;DR

1. **Loop** = repeat code. Go has only `for`.
2. **Traditional** = `for i := 0; i < n; i++ { }`
   - init once, then check, body, post.
3. **Condition-only** = `for x < 100 { }`. Go's "while".
4. **Infinite** = `for { }`. Leave with `break`.
5. **range** = `for i, v := range collection { }`
   - arrays, slices, strings (runes), maps (random order), channels, integers.
6. **break** = leave. **continue** = next trip. **label** = reach an outer loop. **goto** = avoid.
7. **Nested loop** = the inner loop runs fully for each outer trip.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `for (i := 0; i < 5; i++)` | Parentheses are needed | No parentheses in Go | A syntax error. |
| `while x < 5 { }` | Go has `while` | Use `for x < 5 { }` | `undefined: while` |
| Forgetting to change the condition | The loop stops by itself | Something must change it | The loop never ends. |
| `i <= len(list)` | The last index is `len` | The last index is `len - 1` | `index out of range` panic. |
| Printing a map in a loop and expecting order | Maps keep insertion order | Map order changes each run | Output order changes. |
| `break` in a nested loop to stop both | `break` leaves all loops | It leaves only the inner loop | The outer loop keeps going. |
| `for i, v := range marks` with `i` unused | Unused loop variables are fine | Use `_` for the index | `declared and not used: i` |

## Check Yourself

## Exercises

## What to Remember

- Go has one loop keyword: `for`.
- `for i := 0; i < n; i++` counts. `for cond` waits. `for { }` runs forever.
- `range` gives the position and the value of each item.
- Map order changes every run.
- `break` leaves, `continue` skips, labels reach outer loops. Avoid `goto`.
- The inner loop runs fully for every trip of the outer loop.

Next: **Functions**. You will learn how to name a group of steps and reuse it with different values.
