Go range keyword

In Go, the range keyword is used with a Go for loop to iterate over arrays, slices, strings, maps, and channels. Depending on the value being ranged over, each iteration produces one value or two values.

The general form is for values := range expression. You can use both returned values, use only the first value, or discard an unwanted value with the blank identifier _.

Values returned by Go range

The values produced by range depend on the type of the range expression.

Range expressionFirst valueSecond value
Array or sliceIndexElement value
StringByte indexUnicode code point as a rune
MapKeyValue
ChannelReceived elementNone

The second value is optional. For arrays, slices, strings, and maps, omit it when only the index or key is required. For a channel, each iteration returns only the received element.

Go range syntax for one or two values

</>
Copy
// First value only
for first := range collection {
    // use first
}

// First and second values
for first, second := range collection {
    // use first and second
}

// Ignore the first value
for _, second := range collection {
    // use second
}

When neither returned value is needed, use for range collection. This form is useful when an action only needs to run once for every item.

Go range with an array

For an array, range returns the zero-based index first and a copy of the element value second.

Use the array index returned by range

In the following program, only the index returned by range is used. The element is then accessed with evens[index].

example.go

</>
Copy
package main

import "fmt"

func main() {
	var evens = [5] int {2, 4, 6, 8, 10}
	
	// using index returned from range
	for index:= range evens {
		fmt.Printf("evens[%d] = %d \n", index, evens[index])
	}
}

Output

evens[0] = 2
evens[1] = 4
evens[2] = 6
evens[3] = 8
evens[4] = 10

Use the array index and element value

In this program, both values returned by range are assigned: index receives the position and element receives the value at that position.

example.go

</>
Copy
package main

import "fmt"

func main() {
	var evens = [5] int {2, 4, 6, 8, 10}
	
	// using index and element returned from range
	for index,element:= range evens {
		fmt.Printf("evens[%d] = %d \n", index, element)
	}
}

Output

evens[0] = 2
evens[1] = 4
evens[2] = 6
evens[3] = 8
evens[4] = 10

Go range with a slice

A slice is ranged over in the same way as an array. The first value is the index and the second is the element value.

</>
Copy
package main

import "fmt"

func main() {
    languages := []string{"Go", "Java", "Python"}

    for index, language := range languages {
        fmt.Printf("%d: %s\n", index, language)
    }
}

Output

0: Go
1: Java
2: Python

Iterate over slice values without the index

Use _ to discard the index when only the slice element is needed.

</>
Copy
for _, language := range languages {
    fmt.Println(language)
}

Go range with a string

When ranging over a string, Go decodes the UTF-8 text one Unicode code point at a time. The first value is the byte index where the rune begins, and the second value is the rune itself.

Range over an ASCII string by index

This example uses only the index returned by range. Indexing the string with str[index] returns the byte stored at that position.

example.go

</>
Copy
package main

import "fmt"

func main() {
	var str = "Golang"
	
	// using index returned from range
	for index:= range str {
		fmt.Printf("str[%d] = %d \n", index, str[index])
	}
}

Output

str[0] = 71
str[1] = 111
str[2] = 108
str[3] = 97
str[4] = 110
str[5] = 103

Because this example contains ASCII characters only, each character occupies one byte. For general Unicode text, byte indexes may increase by more than one.

Get the byte index and rune from a string

This example assigns both the byte index and the rune returned during each iteration.

example.go

</>
Copy
package main

import "fmt"

func main() {
	var str = "Golang"
	
	// using index and element returned from range
	for index,element:= range str {
		fmt.Printf("str[%d] = %d \n", index, element)
	}
}

Output

str[0] = 71
str[1] = 111
str[2] = 108
str[3] = 97
str[4] = 110
str[5] = 103

Range over Unicode characters correctly

Use the rune value returned by range when the string may contain multibyte UTF-8 characters.

</>
Copy
package main

import "fmt"

func main() {
    text := "Go✓"

    for index, character := range text {
        fmt.Printf("byte index %d: %c\n", index, character)
    }
}

Output

byte index 0: G
byte index 1: o
byte index 2: ✓

The check mark occupies multiple UTF-8 bytes, but range returns it as one rune.

Go range with a map

For a map, range returns a key first and the corresponding value second. Map iteration order is not specified, so programs should not depend on keys appearing in a fixed order.

Use each map key returned by range

In this example, color receives each map key. The value is then obtained with colorMap[color].

example.go

</>
Copy
package main

import "fmt"

func main() {
	var colorMap = make(map[string]string)
	colorMap["white"] = "#FFFFFF"
	colorMap["black"] = "#000000"
	colorMap["red"] = "#FF0000"
	colorMap["blue"] = "#0000FF"
	colorMap["green"] = "#00FF00"
	
	for color := range colorMap {
      fmt.Println("Hex value of", color, "is", colorMap[color])
   }
}

Possible output

Hex value of white is #FFFFFF
Hex value of black is #000000
Hex value of red is #FF0000
Hex value of blue is #0000FF
Hex value of green is #00FF00

The exact order may differ between runs because map iteration order is unspecified.

Get each map key and value

This example assigns both values returned by range: color receives the key and hex receives its value.

example.go

</>
Copy
package main

import "fmt"

func main() {
	var colorMap = make(map[string]string)
	colorMap["white"] = "#FFFFFF"
	colorMap["black"] = "#000000"
	colorMap["red"] = "#FF0000"
	colorMap["blue"] = "#0000FF"
	colorMap["green"] = "#00FF00"
	
	for color, hex := range colorMap {
      fmt.Println("Hex value of", color, "is", hex)
   }
}

Possible output

Hex value of white is #FFFFFF
Hex value of black is #000000
Hex value of red is #FF0000
Hex value of blue is #0000FF
Hex value of green is #00FF00

Go range with a channel

Ranging over a channel receives values until the channel is closed. A range loop over an open channel waits for the next value, so the sender must eventually close the channel when no more values will be sent.

</>
Copy
package main

import "fmt"

func main() {
    numbers := make(chan int)

    go func() {
        numbers <- 10
        numbers <- 20
        numbers <- 30
        close(numbers)
    }()

    for number := range numbers {
        fmt.Println(number)
    }
}

Output

10
20
30

Generate a numeric range from 1 to 10 in Go

To iterate from one number to another with explicit start, stop, and step values, use the three-part form of the Go for loop. This is the clearest approach for ranges such as 1 to 10 or increments greater than one.

</>
Copy
package main

import "fmt"

func main() {
    for number := 1; number <= 10; number++ {
        fmt.Println(number)
    }
}

Use a custom step in a Go numeric loop

Change the post statement to control the step. The following loop prints the odd numbers from 1 through 9.

</>
Copy
for number := 1; number <= 10; number += 2 {
    fmt.Println(number)
}

Common Go range mistakes

  • Assuming map order is fixed: sort the keys separately when deterministic output is required.
  • Treating a string index as a character position: the index returned by range is a byte index.
  • Using str[index] for Unicode characters: direct string indexing returns a byte, while range returns decoded runes.
  • Forgetting to close a channel: a range loop waits until the channel is closed.
  • Expecting the ranged element to be a writable reference: the element variable receives a value; use the index to update an array or slice element.

Go range FAQs

What is range in Go?

range is a clause used with a for loop to iterate over arrays, slices, strings, maps, and channels. It produces values appropriate to the type being iterated.

How do I ignore the index in a Go range loop?

Use the blank identifier: for _, value := range items. The underscore discards the index.

Does Go range preserve map insertion order?

No. Map iteration order is unspecified. Collect and sort the keys before iteration when a stable order is required.

Why does range over a Go string return byte indexes?

Go strings contain UTF-8 encoded bytes. The index returned by range identifies the byte position at which each decoded rune begins.

How do I loop from 1 to 10 with a step in Go?

Use a three-part for loop, such as for i := 1; i <= 10; i += 2. Change the initial value, condition, and increment to define the numeric sequence.

Go range editorial QA checklist

  • Confirm the return values are described correctly for arrays, slices, strings, maps, and channels.
  • Verify that string examples distinguish byte indexes, bytes, and runes.
  • Label map output as possible output and do not imply a guaranteed iteration order.
  • Ensure channel examples close the channel before the range loop can finish.
  • Use a standard three-part for loop when demonstrating numeric start, end, or step values.

Summary of range loops in Go

Use range with a Go for loop to traverse collections and channels. Arrays and slices return an index and element, strings return a byte index and rune, maps return a key and value, and channels return received elements until closed. In this Go Tutorial, we covered these forms with examples and also showed how to write numeric loops with custom bounds and steps.