Functions on the left-hand side of a for-range statement

June 12, 2024

For statements with range clause

Function calls on the left are evaluated once per iteration.

This small sentence is easy to overlook. What does it mean?

It means if you have any function calls on the left hand side of the for range statement, they are executed per iteration. What would that even look like? It’s probably a rare occurrence, but here’s an example in the playground:

func main() {
	for _, m()["foo"] = range []string{"foo", "bar", "baz"} {
	}
	fmt.Println(globalMap)
}

var globalMap = make(map[string]string)

func m() map[string]string {
	fmt.Println("m() called")
	return globalMap
}

Notice the call to m() in the left-hand side of the for-range statement. The function m() returns a map, which is in turn dereferenced to receive the range assignment.

But this code also proves that m() is called for each iteration of the loop, as it outputs:

m() called
m() called
m() called
map[foo:baz]

indicating three calls to m(), before showing the final output of the map returned by m().

Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Iteration over strings

For statements with range clause … For a string value, the “range” clause iterates over the Unicode code points in the string starting at byte index 0. On successive iterations, the index value will be the index of the first byte of successive UTF-8-encoded code points in the string, and the second value, of type rune, will be the value of the corresponding code point. If the iteration encounters an invalid UTF-8 sequence, the second value will be 0xFFFD, the Unicode replacement character, and the next iteration will advance a single byte in the string.


Iteration over arrays and slices

For statements with range clause … For an array, pointer to array, or slice value a, the index iteration values are produced in increasing order, starting at element index 0. If at most one iteration variable is present, the range loop produces iteration values from 0 up to len(a)-1 and does not index into the array or slice itself. For a nil slice, the number of iterations is 0. From this above paragraph, we can be assured that ranging over an array, pointer to array, or slice, will operate in a defined order–from index 0, upward.


The types of iteration variables

For statements with range clause … For each iteration, iteration values are produced as follows if the respective iteration variables are present: Range expression 1st value 2nd value array or slice a [n]E, *[n]E, or []E index i int a[i] E string s string type index i int see below rune map m map[K]V key k K m[k] V channel c chan E, <-chan E element e E integer n integer type value i see below How do we read this table?

Get daily content like this in your inbox!

Subscribe