In Go, for is the only looping keyword: whether you want a golang for loop with init/condition/post, a while-style loop, an infinite golang loop, or a for range walk over a collection, you still write for. This guide matches common searches—go for loop, for loop golang, golang for, for loop in golang, golang for cycle, golang iterate struct fields, golang iterate over interface—with small, copy-pastable programs for slices, maps, strings, structs via reflect, []any with type switches, and channels together with goroutines.
Tested with Go 1.24 on Linux.
Classic for: three-part, while-style, and infinite
Go does not wrap the three clauses in parentheses. A traditional counter loop looks like this:
package main
import "fmt"
func main() {
total := 0
for i := 0; i < 10; i++ {
total += i
}
fmt.Println(total)
}That prints 45.
You can omit the init and post clauses to get a while-style loop (for condition), or omit everything for a forever loop (for { }). Infinite loops need an explicit break, return, or os.Exit; run them locally with care.
package main
import (
"fmt"
"time"
)
func main() {
n := 0
for {
fmt.Println("tick", n)
n++
if n >= 3 {
break
}
time.Sleep(100 * time.Millisecond)
}
}for range on slices and arrays (golang loop over indexes)
for range on a slice yields index and value. You can ignore either with _.
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5}
for i, v := range nums {
fmt.Printf("index=%d value=%d\n", i, v)
}
}for range on maps and strings
Maps
Map iteration returns a key and value on each iteration. Order is not defined—do not assume sorted keys.
package main
import "fmt"
func main() {
user := map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Country": "Go Land",
"Email": "john@example.com",
}
for k, v := range user {
fmt.Printf("%s = %s\n", k, v)
}
}Strings: runes and indexes
Ranging over a string yields the byte offset of each UTF-8 code point (rune), not a fixed “character index” in all languages.
package main
import "fmt"
func main() {
s := "Hi! 世"
for i, r := range s {
fmt.Printf("offset=%d rune=%U char=%c\n", i, r, r)
}
}Use []byte(s) if you need to loop raw bytes instead.
Golang iterate struct fields with reflect
There is no for syntax that walks struct fields directly. For golang iterate struct fields at runtime, use reflect.Value on a struct value (or pointer with Elem() after reflect.ValueOf(&t)).
package main
import (
"fmt"
"reflect"
)
type User struct {
FirstName string
LastName string
Email string
Phone int
}
func main() {
u := User{"John", "Doe", "john@example.com", 1234567}
v := reflect.ValueOf(u)
t := v.Type()
for i := 0; i < v.NumField(); i++ {
fmt.Printf("Field: %s\tValue: %v\n", t.Field(i).Name, v.Field(i).Interface())
}
}This pattern lists exported fields in declaration order. For stable wire formats or JSON-driven iteration, prefer marshaling (see encoding/json) or explicit field access instead of reflection when you can.
Golang iterate over interface{} / any slices
For golang iterate over interface-shaped data, store heterogeneous values in []any and use a type switch inside the loop.
package main
import "fmt"
func main() {
items := []any{42, "hello", 3.14}
for _, item := range items {
switch v := item.(type) {
case int:
fmt.Println("int:", v)
case string:
fmt.Println("string:", v)
case float64:
fmt.Println("float64:", v)
default:
fmt.Println("other")
}
}
}for range on channels
Receiving with for msg := range ch continues until close(ch). Only the sender side should close a channel when the protocol requires it.
package main
func sendUsers(c chan string) {
users := []string{"user1", "user2", "user3"}
for _, u := range users {
c <- u
}
close(c)
}
func main() {
c := make(chan string, 3)
go sendUsers(c)
for msg := range c {
println(msg)
}
}Example output:
user1
user2
user3Summary
Golang for loop and go for loop both mean the same for keyword: use a three-part form for counters, for condition for loops that read like while, and for range for slices, maps, strings, channels, and generic slices. For loop in golang map code must not rely on iteration order. Golang iterate struct fields at runtime usually means reflect over a struct value. Golang iterate over interface-shaped data is idiomatically a []any slice, for range, and a type switch. Together with break, continue, and labeled breaks where needed, this covers the day-to-day golang loop toolbox.
References
Frequently Asked Questions
1. Is there only one golang for loop keyword?
for; there is no separate while or do—you write for condition or for { } instead.2. How do I golang iterate over struct fields?
reflect on a struct value and loop i := 0; i < v.NumField(); i++, reading v.Type().Field(i).Name and v.Field(i); exported fields are straightforward, while unexported fields need different techniques.3. How is golang iterate over interface values handled?
[]any (or []interface{}), for range the slice, then use a type switch on each element to branch on concrete types.4. Does ranging over a map have a fixed order?
for range over a map.5. What does `for range` on a string yield?
rune (Unicode code point), not a byte, because strings are UTF-8; use []byte if you need raw bytes.
