liveBook · Manning

Range loop

As explained in Go in Action, Second Edition

A range loop is a Go for-loop form that iterates over the elements or entries of a supported collection and can provide each element's index and value.

A range loop visits each item in a collection without manually checking its length. Use it when code should work for any number of items, including an empty slice: the loop simply runs zero times. section 4.2.8 section 2.9

For an array or slice, `for i := range items` supplies indices. `for i, item := range items` supplies each index and a copy of its value. Write `for _, item := range items` when the index is unnecessary. section 4.1.4 section 2.9

Listing 2.47 The two different range loop forms for slices
stringList := []string{"A", "B", "C"}

// Single-value form gets just the index.
for index := range stringList {
	fmt.Println(index)
}
// Output:
// 0
// 1
// 2

// Two-value form gets the index and a copy of the value.
for index, value := range stringList {
	fmt.Println(index, value)
}
// Output:
// 0 A
// 1 B
// 2 C

// Discarding the index.
for _, value := range stringList {
	fmt.Println(value)
}
// Output:
// A
// B
// C

Compare the one-value, two-value, and discarded-index forms on the same slice. section 2.9

Process every filename

`for _, filename := range os.Args[1:]` visits command-line filenames while skipping the program name. If opening one file fails, log the error and `continue` so the remaining files can still be processed. section 2.9

A ranged value is a copy. Changing that variable does not change an array element; use the supplied index to assign to the element instead. If processing requires reverse order or skipping items, an index-controlled `for` loop is a better fit. section 4.1.4

Listing 4.59 Using a range statement Instead of explicit indices
func printMedalists3(raceName string, contestants []string) {
	fmt.Printf("Results for %s:\n", raceName)
	for place, contestant := range contestants {
		switch place {
		case 0:
			fmt.Printf("Gold Medal: %s\n", contestant)
		case 1:
			fmt.Printf("Silver Medal: %s\n", contestant)
		case 2:
			fmt.Printf("Bronze Medal: %s\n", contestant)
		default:
			fmt.Printf("Finisher: %s\n", contestant)
			// or just return
		}
	}
}

func main() {
	race1 := []string{"Sally", "Steve", "Jo", "Adam"}
	race2 := []string{"Jon", "Jen"}
	race3 := []string{}

	printMedalists3("Race 1", race1)
	// Race 2 only has two contestants, but we still need to list them!
	printMedalists3("Race 2", race2)
	// Throw in a race with no contestants at all.
	printMedalists3("Race 3", race3)
}

A results function uses the range index to label finishers without assuming the slice contains at least three people. section 4.2.8

Range has collection-specific details. Over a string, it supplies each character as a rune and the byte index where that character starts. Over a map, it supplies a key and optionally a copy of its value; map iteration order is unspecified. Deleting selected entries while ranging over a map is safe if the map is not being accessed elsewhere at the same time. Range also works with channels. section 3.8.5 section 4.3.5 section 2.9

How Go in Action, Second Edition covers it

How deep it goes
Explains assignment forms, copied values, string indices, and map order; defers channel behavior.
Examples
Demonstrates multiple-file word counting, Unicode character positions, race results, and map filtering.
What it assumes
Assumes familiarity with Go for loops and collections while teaching range assignment forms through examples.
What you can do after
Apply it via Go's range clause to traverse variable-length collections and choose indices when modifying array elements.
How it connects
Connects range to slices, arrays, Unicode strings, maps, the blank identifier, and index-controlled for loops.

Also explained in

Compare how 3 books explain range loop →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Action, Second Edition. The section links point to the parts of the book it draws on.