Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The for range loop is a control flow construct in Go used to iterate over built-in iterable data structures and iterator functions. It abstracts the boilerplate of traditional loops, yielding one or two iteration variables per step depending on the type of the iterable expression evaluated on the right side of the range keyword.

Base Syntax

The syntax allows declaring up to two iteration variables:
// Two-variable iteration
for first, second := range iterable {
    // loop body
}

// One-variable iteration
for first := range iterable {
    // loop body
}

Iteration Mechanics by Type

The arity (number of variables yielded) and the semantics of the iteration variables depend strictly on the type of the iterable.
  • Arrays and Slices (Yields 2 variables):
    • first: Integer index (starting at 0).
    • second: A copy of the element at that index.
  • Strings (Yields 2 variables):
    • first: The starting byte index of the current Unicode character.
    • second: A rune (an int32 representing the Unicode code point).
    • UTF-8 Semantics: Because characters can be multi-byte, the index may not increment sequentially by 1. If the loop encounters an invalid UTF-8 byte sequence, the second variable yields the Unicode replacement character (\uFFFD) and the first variable advances by exactly one byte.
  • Maps (Yields 2 variables):
    • first: The map key.
    • second: The map value.
    • Behavioral Note: Map iteration order is intentionally non-deterministic. Go randomizes the starting hash bucket to prevent reliance on map iteration order.
    • Modification Rules: If a map entry is removed before it is reached during iteration, it will not be produced. If an entry is added during iteration, it may or may not be produced.
  • Channels (Yields 1 variable):
    • first: The value received from the channel.
    • Behavioral Note: The loop blocks until a value is available and terminates only when the channel is closed and all values sent prior to the close have been received.
  • Integers (Go 1.22+) (Yields 1 variable):
    • first: An integer incrementing from 0 up to iterable - 1.
  • Functions / Iterators (Go 1.23+) (Yields 1 or 2 variables):
    • Go supports ranging over any function that matches specific iterator signatures: func(yield func(V) bool) (yields 1 variable, the value) or func(yield func(K, V) bool) (yields 2 variables, key and value).
    • The standard library provides iter.Seq[V] and iter.Seq2[K, V] as convenient aliases for these signatures, but they are not strictly required for the range loop to function.
    • The for range loop body acts as an implicit closure passed to the iterator function, executing for each value yielded by the sequence.

Syntax Variations and Variable Omission

Go enforces strict variable usage; declared but unused variables cause compiler errors. The rules for omitting variables depend on whether the iterable yields one or two variables. Two-Variable Iterables (Arrays, Slices, Strings, Maps, 2-ary Functions): By default, these yield a key/index and a value.
  • Omitting the value: Drop the second variable entirely. The single variable will represent the key/index.
for key := range mapOrSlice {
    // value is not evaluated or assigned
}
  • Omitting the key: Use the blank identifier (_) for the first variable.
for _, value := range mapOrSlice {
    // key is discarded
}
One-Variable Iterables (Channels, Integers, 1-ary Functions): These yield only a value.
  • Standard usage: The single variable represents the value.
for value := range channelOrInt {
    // processes the value
}
  • Compiler Error: Attempting to use the blank identifier to “skip a key” (e.g., for _, value := range channel) will produce a too many variables in range compiler error, as there is no second variable to assign.
Zero Variables (All Iterables): If the loop is executed purely for side effects (or to drain a channel), all variables can be omitted.
for range iterable {
    // executes for each element/yield, or until the channel is closed
}

Memory Semantics and Evaluation Rules

1. Value Copying The value variable in a for range loop is a copy of the element from the underlying data structure. Mutating the value variable does not modify the original iterable. To mutate the original structure, you must index into it using the key:
for i, v := range mySlice {
    v = v * 2       // Modifies the local copy 'v', mySlice is unchanged
    mySlice[i] = v  // Modifies the underlying mySlice with the updated value
}
2. Single Evaluation of the Iterable The expression provided to range is evaluated exactly once before the loop begins. This has critical implications depending on the underlying type:
  • Arrays: Because the expression is evaluated once, ranging over an array copies the entire array. Mutations made to the original array during iteration are not seen by the loop.
  • Array Pointers (*[N]T): To avoid copying the entire array, you can range over a pointer to the array. This ensures that mutations to the array’s elements during iteration are visible to the loop.
  • Slices: Ranging over a slice only copies the slice header (which contains the pointer to the backing array, length, and capacity). Therefore, mutations to the underlying array’s elements during iteration are visible to the loop. However, appending to the slice will not increase the number of loop iterations, as the original length was evaluated at the start.
3. Variable Scoping (Go 1.22 Update) As of Go 1.22, iteration variables are scoped per-iteration. In older versions of Go (1.21 and below), the variables were scoped per-loop, meaning the same memory address was reused and overwritten on each iteration. This historical behavior required developers to manually shadow variables when capturing them inside closures or goroutines to prevent race conditions or logic errors.
Master Go with Deep Grasping Methodology!Learn More