763

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

Tiago Peczenyj
  • 4,387
  • 2
  • 22
  • 35
tatsuhirosatou
  • 25,149
  • 14
  • 39
  • 40
  • 1
    check out: http://groups.google.com/group/golang-nuts/browse_thread/thread/e2966ccdfe910e14?pli=1 – Kakashi Oct 16 '11 at 05:19
  • 2
    The usage of `range` in `for` loops is also mentioned in the "An Interlude about Types" section (towards its end) of the Go tutorial. – kostix Oct 16 '11 at 12:31

9 Answers9

1105

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 25
    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. – Brent Bradburn Dec 08 '18 at 20:15
  • I know in Python and C it's frequent to use underscore as a function for localization ( i.e. the [gettext](https://docs.python.org/3/library/gettext.html#localizing-your-module) ). Would the use of underscore cause any problems in Go ? Does Go even use the same library for localization ? – Sergiy Kolodyazhnyy Dec 29 '18 at 09: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 Apr 05 '19 at 15:40
  • See [Moshe Revah's answer](https://stackoverflow.com/a/34333832/1365918) below for more usage examples of `for...range`. Includes slices, maps and channels. – kapad Sep 08 '20 at 08:33
224

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
    }
}
dev.bmax
  • 8,998
  • 3
  • 30
  • 41
Zippo
  • 15,850
  • 10
  • 60
  • 58
  • 21
    Although the OP only asked for slice usage, I prefer this answer, because most will eventually need the other usages as well. – domoarigato Aug 02 '16 at 01: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](https://tour.golang.org/concurrency/4) – colm.anseo Oct 10 '17 at 22:25
  • Thought the same when reading it, `for { ... }` stands for an infinite loop. – Levite Dec 22 '17 at 09: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 Mar 22 '22 at 14:48
23

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nisal Edu
  • 7,237
  • 4
  • 28
  • 34
  • 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). – Gwyneth Llewelyn Jun 11 '20 at 22:03
14

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.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amitesh Bharti
  • 14,264
  • 6
  • 62
  • 62
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?

ceving
  • 21,900
  • 13
  • 104
  • 178
  • 3
    Add a `,` and it's clearer where the `for` condition ends: http://play.golang.org/p/pcRg6WdxBd - This is actually the first time I've found a counter argument to the `go fmt` style, thanks! – topskip Jul 07 '14 at 09:35
  • @topskip both are go fmt valid; just pick the best one :) – Filip Haglund Jun 14 '15 at 01: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 Jun 14 '15 at 07:15
  • 12
    In my opinion, this answer is unreasonably complex for the targeted question. – AndreasHassing Feb 02 '16 at 22:08
  • @AndreasHassing How to do it instead without introducing redundancy? – ceving Jan 16 '19 at 08: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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
robstarbuck
  • 6,893
  • 2
  • 41
  • 40
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

jpihl
  • 7,941
  • 3
  • 37
  • 50
1

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
}
Blue Leo
  • 11
  • 1
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jose78
  • 21
  • 6
  • How is it a for-each loop? Isn't it just list processing? Can you [elaborate](https://stackoverflow.com/posts/63549127/edit) in your answer? (But ***without*** "Edit:", "Update:", or similar - the question/answer should appear as if it was written today.) – Peter Mortensen May 23 '22 at 13:29