786

Is there a foreach construct in the Go language? Can I iterate over a slice or array using a for?

2

9 Answers 9

1130

From For statements with range clause:

A "for" statement with a "range" clause iterates through all entries of an array, slice, string or map, or values received on a channel. For each entry it assigns iteration values to corresponding iteration variables and then executes the block.

As an example:

for index, element := range someSlice {
    // index is the index where we are
    // element is the element from someSlice for where we are
}

If you don't care about the index, you can use _:

for _, element := range someSlice {
    // element is the element from someSlice for where we are
}

The underscore, _, is the blank identifier, an anonymous placeholder.

4
  • 31
    In this example, element is the value of the element (a copy) -- it is not the element itself. Although you can assign to element, this will not effect the underlying sequence. Commented Dec 8, 2018 at 20:15
  • I know in Python and C it's frequent to use underscore as a function for localization ( i.e. the gettext ). Would the use of underscore cause any problems in Go ? Does Go even use the same library for localization ? Commented Dec 29, 2018 at 9:05
  • 4
    @SergiyKolodyazhnyy Py docs says "(gettext) function is usually aliased as _() in the local namespace" which is just by convention, it's not part of the localization lib. The underscore _ is a valid label, and it's also convention in Go (and Python and Scala and other langs) to assign to _ for return values you won't use. The scope of _ in this example is restricted to the body of the for loop. If you have a package-scoped function _ then it would be shadowed inside the scope of the for loop. There's a few packages for localization, I've not seen any use _ as a function name.
    – Davos
    Commented Apr 5, 2019 at 15:40
  • See Moshe Revah's answer below for more usage examples of for...range. Includes slices, maps and channels.
    – kapad
    Commented Sep 8, 2020 at 8:33
229

Go has a foreach-like syntax. It supports arrays/slices, maps and channels.

Iterate over an array or a slice:

// index and value
for i, v := range slice {}

// index only
for i := range slice {}

// value only
for _, v := range slice {}

Iterate over a map:

// key and value
for key, value := range theMap {}

// key only
for key := range theMap {}

// value only
for _, value := range theMap {}

Iterate over a channel:

for v := range theChan {}

Iterating over a channel is equivalent to receiving from a channel until it is closed:

for {
    v, ok := <-theChan
    if !ok {
        break
    }
}
4
  • 22
    Although the OP only asked for slice usage, I prefer this answer, because most will eventually need the other usages as well. Commented Aug 2, 2016 at 1:36
  • 4
    important distinction about the chan usage: ranging over a channel will gracefully exit the loop if the writer closes the channel at some point. In the for {v := <-theChan} equivalent, it will not exit on channel close. You can test for this via the second ok return value. TOUR EXAMPLE
    – colm.anseo
    Commented Oct 10, 2017 at 22:25
  • Thought the same when reading it, for { ... } stands for an infinite loop.
    – Levite
    Commented Dec 22, 2017 at 9:44
  • How about just for without both key, value.I just want to run specific len. And do nothing with array. Ex: for _ := range slice{}
    – Duong Phan
    Commented Mar 22, 2022 at 14:48
24

Following is the example code for how to use foreach in Go:

package main

import (
    "fmt"
)

func main() {

    arrayOne := [3]string{"Apple", "Mango", "Banana"}

    for index,element := range arrayOne{

        fmt.Println(index)
        fmt.Println(element)

    }

}

This is a running example https://play.golang.org/p/LXptmH4X_0

1
  • 2
    Sometimes it's the simplest example that is the most useful. Thanks! I've got nothing against the most esoteric answers from the other commenters — they certainly illustrate the intricacies of very idiomatic Go programming, to the point that they become... unreadable and hard to follow — but I prefer your answer: it goes straight to the core with the simplest possible example (which works and it's obvious why it works). Commented Jun 11, 2020 at 22:03
16

Yes, range:

The range form of the for loop iterates over a slice or map.

When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.

Example:

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range pow {
        fmt.Printf("2**%d = %d\n", i, v)
    }

    for i := range pow {
        pow[i] = 1 << uint(i) // == 2**i
    }
    for _, value := range pow {
        fmt.Printf("%d\n", value)
    }
}
  • You can skip the index or value by assigning to _.
  • If you only want the index, drop the , value entirely.
13

The following example shows how to use the range operator in a for loop to implement a foreach loop.

func PrintXml (out io.Writer, value interface{}) error {
    var data []byte
    var err error

    for _, action := range []func() {
        func () { data, err = xml.MarshalIndent(value, "", "  ") },
        func () { _, err = out.Write([]byte(xml.Header)) },
        func () { _, err = out.Write(data) },
        func () { _, err = out.Write([]byte("\n")) }} {
        action();
        if err != nil {
            return err
        }
    }
    return nil;
}

The example iterates over an array of functions to unify the error handling for the functions. A complete example is at Google´s playground.

PS: it shows also that hanging braces are a bad idea for the readability of code. Hint: the for condition ends just before the action() call. Obvious, isn't it?

5
  • 3
    Add a , and it's clearer where the for condition ends: play.golang.org/p/pcRg6WdxBd - This is actually the first time I've found a counter argument to the go fmt style, thanks!
    – topskip
    Commented Jul 7, 2014 at 9:35
  • @topskip both are go fmt valid; just pick the best one :)
    – Drathier
    Commented Jun 14, 2015 at 1:29
  • @FilipHaglund It is not the point if it is valid. The point is that IMO it's clearer where the for condition ends in that particular case above.
    – topskip
    Commented Jun 14, 2015 at 7:15
  • 12
    In my opinion, this answer is unreasonably complex for the targeted question. Commented Feb 2, 2016 at 22:08
  • @AndreasHassing How to do it instead without introducing redundancy?
    – ceving
    Commented Jan 16, 2019 at 8:07
12

You can in fact use range without referencing its return values by using for range against your type:

arr := make([]uint8, 5)
i,j := 0,0
for range arr {
    fmt.Println("Array Loop", i)
    i++
}

for range "bytes" {
    fmt.Println("String Loop", j)
    j++
}

https://play.golang.org/p/XHrHLbJMEd

2
  • 3
    Good to know but that's not going to be useful in most cases
    – Sridhar
    Commented Sep 5, 2016 at 17:39
  • Agreed @Sridhar it's pretty niche. Commented Sep 5, 2016 at 18:30
2

I'm seeing a lot of examples using range. Just a heads up that range creates a copy of whatever you're iterating over. If you make changes to the contents in a foreach range you will not be changing the values in the original container, in that case you'll need a traditional for loop with an index you increment and deference indexed reference. E.g.:

for i := 0; i < len(arr); i++ {
    element := &arr[i]
    element.Val = newVal
}
1

This may be obvious, but you can inline the array like so:

package main

import (
    "fmt"
)

func main() {
    for _, element := range [3]string{"a", "b", "c"} {
        fmt.Print(element)
    }
}

outputs:

abc

https://play.golang.org/p/gkKgF3y5nmt

0

I have just implemented this library: https://github.com/jose78/go-collection.

This is an example of how to use the Foreach loop:

package main

import (
    "fmt"

    col "github.com/jose78/go-collection/collections"
)

type user struct {
    name string
    age  int
    id   int
}

func main() {
    newList := col.ListType{user{"Alvaro", 6, 1}, user{"Sofia", 3, 2}}
    newList = append(newList, user{"Mon", 0, 3})

    newList.Foreach(simpleLoop)

    if err := newList.Foreach(simpleLoopWithError); err != nil{
        fmt.Printf("This error >>> %v <<< was produced", err )
    }
}

var simpleLoop col.FnForeachList = func(mapper interface{}, index int) {
    fmt.Printf("%d.- item:%v\n", index, mapper)
}


var simpleLoopWithError col.FnForeachList = func(mapper interface{}, index int) {
    if index > 1{
        panic(fmt.Sprintf("Error produced with index == %d\n", index))
    }
    fmt.Printf("%d.- item:%v\n", index, mapper)
}

The result of this execution should be:

0.- item:{Alvaro 6 1}
1.- item:{Sofia 3 2}
2.- item:{Mon 0 3}
0.- item:{Alvaro 6 1}
1.- item:{Sofia 3 2}
Recovered in f Error produced with index == 2

ERROR: Error produced with index == 2
This error >>> Error produced with index == 2
 <<< was produced

Try this code in playGrounD.

1
  • How is it a for-each loop? Isn't it just list processing? Can you elaborate in your answer? (But without "Edit:", "Update:", or similar - the question/answer should appear as if it was written today.) Commented May 23, 2022 at 13:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.