for Loops & range
Go is refreshingly minimal: there is exactly one loop keyword, for , and it covers every job — counted loops, while-style loops, infinite loops, and (with range ) walking over slices, maps and strings. Master these forms and you can iterate over anything.
Learn for Loops & range in our free Go course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ One Keyword, Three Shapes
Every for in Go is a variation on the same keyword. The full form has three parts separated by semicolons: an init statement, a condition , and a post statement. Drop the init and post and you have a while loop. Drop everything and you have an infinite loop you exit with break .
2️⃣ break, continue & Nesting
break leaves the loop immediately; continue skips the rest of the current iteration and jumps to the next. Loops nest freely — an outer loop for rows, an inner loop for columns. (Go also supports labelled breaks to exit an outer loop from inside an inner one, which you'll meet later.)
3️⃣ range — Walk Any Collection
range is how you iterate collections idiomatically. Over a slice it yields the index and the value ; over a map it yields the key and value (in random order, by design — never rely on map order); over a string it yields the byte index and the rune . When you don't need the index or key, discard it with the blank identifier _ .
Your turn — make a countdown with a three-part loop that decrements.
Now find the best score with a range loop. You don't need the index here.
🧩 Reorder Challenge
These lines sum a slice with range , but they're scrambled. Put them in order so the program prints 6 (assume a func main wraps them).
- nums := []int{1, 2, 3}
- for _, n := range nums {
- fmt.Println(total)
Why: you must create the slice and the accumulator ( total := 0 ) before the loop can use them. The for header opens the block, the body total += n runs once per element, the brace closes the loop, and only then can you print the final total: 1+2+3 = 6.
Pro Tips
- 💡 Prefer range over manual indexing when walking a whole collection — it's clearer and avoids off-by-one bugs.
- 💡 Never depend on map iteration order. Go randomizes it on purpose; sort the keys first if you need a stable order.
- 💡 Range over a string for characters , not s[i] — indexing gives raw bytes, which breaks on non-ASCII text.
- 💡 Use a labelled break (e.g. break outer ) to escape nested loops cleanly instead of a flag variable.
Common Errors (and the fix)
- Infinite loop that never ends — you forgot to advance the counter (the i++ post-statement) or your condition can never become false. Double-check the exit condition.
- "i declared and not used" in a range loop — you took the index but never used it. Replace it with _ .
- "cannot range over int" — older Go can't range over a plain number. Range over a slice/map/string, or use a three-part for . (Go 1.22+ does allow for i := range 5 .)
- Off-by-one — i <= len(s) reads one past the end. Use i < len(s) , or better, range.
📋 Quick Reference
Goal
Syntax
Count 0..n-1
for i := 0; i < n; i++ { }
While
for cond { }
Infinite
for { ... break }
Slice items
for i, v := range s { }
Values only
for _, v := range s { }
Map entries
for k, v := range m { }
🧠 Quick Recall
Predict the output before you reveal the answer.
012 — i runs 0, 1, 2 and stops when i reaches 3 because the condition i < 3 is then false.
s := []string{"a","b"}; for i, v := range s { fmt.Print(i, v) }
0 a1 b — range yields index 0 with "a", then index 1 with "b". (Println-style spacing: each pair prints with a space between i and v.)
for i := 1; i <= 4; i++ { if i == 2 { continue }; fmt.Print(i) }
134 — when i is 2, continue skips the print and moves to the next iteration, so 2 is omitted.
Frequently Asked Questions
Go doesn't have one — a for with only a condition is a while loop: for x < 10 { } . One keyword, fewer surprises.
Q: Why does my map print in a different order each run?
Go deliberately randomizes map iteration order so you never accidentally rely on it. If you need a fixed order, collect the keys into a slice and sort them first.
Q: Can I loop a fixed number of times without a counter variable?
In Go 1.22+ yes: for range 5 { } runs five times. On older versions use a three-part loop and ignore the counter.
Mini-Challenge: Count Vowels
Range over the string, inspect each rune, and tally the vowels. Write it yourself and match the example output.
🎉 Lesson Complete!
- ✅ for is Go's only loop — counted, while, and infinite forms
- ✅ break exits; continue skips to the next iteration
- ✅ range yields index+value (slices), key+value (maps), index+rune (strings)
- ✅ Discard what you don't need with the blank identifier _
- ✅ Never rely on map iteration order — it's randomized
- ✅ Next lesson: Arrays — fixed-size sequences and the foundation of slices
Practice quiz
How many loop keywords does Go have?
- three: for, while, do
- two: for and while
- one: for
- none, it uses recursion
Answer: one: for. for is Go's only loop keyword; it covers counted, while, and infinite forms.
What does for i := 0; i < 3; i++ { fmt.Print(i) } print?
- 012
- 123
- 0123
- 0 1 2
Answer: 012. i runs 0, 1, 2 and stops when i reaches 3, printing 012 with no spaces.
How do you write a while loop in Go?
- while cond { }
- loop cond { }
- do { } while cond
- for cond { }
Answer: for cond { }. A for with only a condition is Go's while loop.
What does break do inside a loop?
- skips to the next iteration
- leaves the loop entirely
- restarts the loop
- returns from the function
Answer: leaves the loop entirely. break exits the loop immediately; continue skips to the next iteration.
What does continue do?
- skips the rest of this iteration and moves to the next
- exits the loop
- pauses the loop
- breaks all nested loops
Answer: skips the rest of this iteration and moves to the next. continue jumps to the next iteration, skipping the rest of the current body.
Ranging over a slice with for i, v := range s yields...
- value then index
- key and value
- index and value
- only the value
Answer: index and value. Over a slice, range gives the index and the value.
Ranging over a map yields its entries in what order?
- sorted by key
- random order by design
- insertion order
- reverse order
Answer: random order by design. Go deliberately randomizes map iteration order; never rely on it.
Ranging over a string with for i, r := range s yields...
- rune index and byte
- two runes
- index and string
- byte index and rune
Answer: byte index and rune. Over a string, range yields the byte index and the rune at that position.
How do you discard the index in a range loop?
- omit it: for v := range s
- use the blank identifier: for _, v := range s
- use nil
- use skip
Answer: use the blank identifier: for _, v := range s. Replace the index with the blank identifier _ when you don't need it.
What prints: for i := 1; i <= 4; i++ { if i == 2 { continue }; fmt.Print(i) }?
- 1234
- 234
- 134
- 124
Answer: 134. When i is 2, continue skips the print, so 2 is omitted, giving 134.
Continue this course
- Previous: Control Flow (if, switch)
- Next: Arrays