Golang for loop and `for range`: slices, maps, structs, interfaces, channels

Golang for loop and go for loop guide: for loop in golang syntax, golang for cycle with three-part and while-style loops, for range over slices, maps, strings, golang iterate struct fields with reflect, golang iterate over interface slices, channels, and infinite for.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang for loop and `for range`: slices, maps, structs, interfaces, channels

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:

go
package main

import "fmt"

func main() {
	total := 0
	for i := 0; i < 10; i++ {
		total += i
	}
	fmt.Println(total)
}
Output

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.

go
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 _.

go
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)
	}
}
Output

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.

go
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)
	}
}
Output

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.

go
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)
	}
}
Output

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)).

go
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())
	}
}
Output

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.

go
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")
		}
	}
}
Output

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.

go
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)
	}
}
Output

Example output:

text
user1
user2
user3

Summary

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?

Yes: every loop uses for; there is no separate while or do—you write for condition or for { } instead.

2. How do I golang iterate over struct fields?

At runtime use 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?

Store values in []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?

No: map iteration order is randomized in Go; do not depend on key order from a single for range over a map.

5. What does `for range` on a string yield?

Each step gives a byte index and a rune (Unicode code point), not a byte, because strings are UTF-8; use []byte if you need raw bytes.
Antony Shikubu

Systems Integration Engineer

Highly skilled software developer with expertise in Python, Golang, and AWS cloud services.