Range in Go
for range iterates over built-in collections and (Go 1.23+) custom iterators.
Range over built-in types
range yields an index/key and a value. For strings, the value is a rune and the index is a byte offset.
Slice and array
xs := []int{10, 20, 30}
for i, v := range xs { _ = i; _ = v }
arr := [3]string{"a","b","c"}
for i, v := range arr { _ = i; _ = v }
Details:
- On slices, the header (ptr/len/cap) is evaluated once. The value
vis a copy of each element. - On arrays, ranging over the array value copies the entire array. Prefer ranging over
&arrorarr[:]to avoid copying large arrays.
// Avoid copying: range over pointer to array or slice view
for i, v := range &arr { _ = i; _ = v }
for i, v := range arr[:] { _ = i; _ = v }
Map (unordered)
m := map[string]int{"a":1, "b":2}
for k, v := range m { _ = k; _ = v }
If order matters, gather keys and sort them before iterating.
keys := make([]string, 0, len(m))
for k := range m { keys = append(keys, k) }
slices.Sort(keys) // Go 1.21+, import "slices"
for _, k := range keys { v := m[k]; _ = v }
Notes:
- Deleting during iteration is safe; newly added keys may or may not be visited.
- Concurrent writes to a map are not safe and can panic; guard with a mutex or use
sync.Map.
String (runes)
for i, r := range "héllo" {
_ = i // byte index
_ = r // rune (Unicode code point)
}
If you need manual control, use utf8.DecodeRuneInString to step through bytes safely.
Channel
ch := make(chan int)
go func(){ defer close(ch); for i:=0;i<3;i++ { ch<-i } }()
for v := range ch { _ = v }
Details:
- Ranging a channel receives until the channel is closed, then the loop exits.
- For senders, always close the channel when done so receivers can terminate.
Tips:
- Map iteration order is not guaranteed; do not rely on it
- Range over strings yields runes, not bytes; use
[]byte(s)for bytes - If you mutate a slice while ranging, prefer ranging over indices
- The value in
for i, v := range xsis a copy; taking&vpoints to the loop variable - Ignore index or value using
_; index-only:for i := range xs { ... }, value-only:for _, v := range xs { ... } - When launching goroutines inside a loop, capture the loop variables:
for i, v := range xs {
i, v := i, v // shadow
go func(){ _ = i; _ = v }()
}
Range over iterators (Go 1.23+)
Go’s iterator primitives (iter.Seq, iter.Seq2) let you implement custom iteration with for range.
Single-value iterator
package main
import (
"fmt"
"iter"
)
// Seq that yields squares up to n-1
func Squares(n int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := 0; i < n; i++ {
if !yield(i*i) { return }
}
}
}
func main() {
for v := range Squares(5) { fmt.Println(v) }
}
Key-value iterator
func Enumerate[T any](xs []T) iter.Seq2[int, T] {
return func(yield func(int, T) bool) {
for i, v := range xs { if !yield(i, v) { return } }
}
}
Composition (map / filter)
func Map[T any, R any](in iter.Seq[T], f func(T) R) iter.Seq[R] {
return func(yield func(R) bool) {
for v := range in {
if !yield(f(v)) { return }
}
}
}
func Filter[T any](in iter.Seq[T], p func(T) bool) iter.Seq[T] {
return func(yield func(T) bool) {
for v := range in {
if p(v) { if !yield(v) { return } }
}
}
}
Bridge to channel
func ToChan[T any](s iter.Seq[T], buf int) <-chan T {
ch := make(chan T, buf)
go func(){
defer close(ch)
for v := range s { ch <- v }
}()
return ch
}
Iterator tips:
- Always check
yieldreturn and stop early if it returns false - Keep iterators lazy; avoid precomputing entire results
- Use
Seq2for index/value or key/value patterns - Favor composition for readability; keep each iterator focused on a single concern
Evaluation semantics (important)
- The range expression is evaluated once at loop entry (slice header, map header, string value, channel reference).
- The iteration variables (
i,v) are reused each iteration; they get new values on each pass. - For arrays: ranging over a value copies it; prefer a slice or pointer-to-array for large arrays.
Summary
rangeworks uniformly over slices, arrays, maps, strings, channels- Go 1.23+ iterators (
iter.Seq,iter.Seq2) enable custom, composable iteration