Go: Range is by Value

TL;DR: The value for each item in a range loop is not by reference. Instead, use the index index := range foos.Bars and index to the item &foos.Bars[index].

I learned a practical lesson today about how the range keyword works in Go. Here's the scenario. I have a struct graph that looks something like this:

type Foo struct {
    Bars []Bar
}
type Bar struct {
    Name string
}

Then, I'm ranging over them, like this:

for _, bar := range foos.Bars {
    setBarName(&bar)
}
for _, bar := range foos.Bars {
    log.Println("Bar Name:", bar.Name)
}

The log statement reveals that the Name field is never set on a bar. As it turns out, when you use range to enumerate items, it will give you a copy of the item instead of a reference to the item. To achieve the desired behavior, we can use the index to get to the item in the collection.

for index := range foo.Bars {
    setBarName(&foo.Bars[index])
}
for index := range foo.Bars {
    log.Println("Bar Name:" + foo.Bars[index].Name)
}