The problem: the same line, again and again
Programs repeat things constantly: greet every user, print every item, add up every price. Before learning Go's for loop, it helps to feel what the work looks like without one.
Say you have a slice of friends and want to greet each one:
friends := []string{"Andy", "Mircea", "David", "Mary"}
fmt.Println("Hey, " + friends[0])
fmt.Println("Hey, " + friends[1])
fmt.Println("Hey, " + friends[2])
fmt.Println("Hey, " + friends[3])
With four friends this is ugly but manageable. The slice is read by index: friends[0] is the first element, and the last valid index is len(friends) - 1, here 3. The + operator joins two strings, so each line prints the greeting followed by one name.
Why this does not scale
Now picture 100 friends. You would write 100 nearly identical lines, and the problems pile up:
- Typos creep in. You will eventually write
friends[17]twice and skipfriends[18], and the program will happily run. - Changing the greeting means editing every line. To switch from
"Hey, "to"Hello, "you must find and change all of them. - The program can't adapt. If the slice has 5 friends tomorrow, the code needs a new line. If it has 3, the extra line indexes past the end and the program panics with
index out of range.
The code repeats because the task repeats: "do this for each element". A loop lets you write that instruction once and let the language repeat it for as many elements as the slice holds.
A glimpse of the alternative
Here is the same greeting written with a loop. You will learn each part in the next lesson, so just notice the size:
for _, friend := range friends {
fmt.Println("Hey, " + friend)
}
The body is written once, and it runs once per element. Whether the slice holds four names or four thousand, these three lines stay the same, and an empty slice simply runs the body zero times. The loop also removes the indexes from your code, so there is no friends[18] to mistype and no index past the end to hit.
The exercise, step by step
The editor starts with a slice of four fruits. The task is to print I eat followed by each fruit, one line per fruit, using only fmt.Println and no loop. This is deliberate. It makes the repetition visible, so the next lesson's loop feels like relief.
- Access each fruit by index. The four elements sit at indexes 0 to 3.
- Join each fruit to
"I eat "with+. The space aftereatbelongs inside the string, because+adds nothing between the pieces. - Print one line per fruit with
fmt.Println, which adds the line break for you.
The solution in Go
fruits := []string{"banana", "orange", "pear", "kiwi"}
fmt.Println("I eat " + fruits[0])
fmt.Println("I eat " + fruits[1])
fmt.Println("I eat " + fruits[2])
fmt.Println("I eat " + fruits[3])
The output is:
I eat banana
I eat orange
I eat pear
I eat kiwi
Look at how little changes from one line to the next: only the index. Whenever you see code like this, a loop can take over.
What to watch for
- Indexes start at 0. The first fruit is
fruits[0], andfruits[4]doesn't exist for a four-element slice. Using it panics at run time with an index out of range error. - The space in the string.
"I eat" + fruits[0]without the trailing space printsI eatbanana. - Quotes versus names.
"fruits[0]"in quotes would print that text literally, instead of the element.
A complete Go program also needs package main, the fmt import and a main function around lines like these, and the compiler rejects an import that nothing uses.
Key takeaways
- Repeating the same statement with only an index changing is a sign that you need a loop.
- Copy-pasted lines drift apart and don't adapt when the slice changes size.
- Next, a
forloop withrangedoes the same job in three lines for any number of elements.