2

example code (edited code snippet): http://play.golang.org/p/eZV4WL-4N_

Why is it that

for x, _ := range body.Personality {
    body.Personality[x].Mutate()
}

successfully mutates the structs' contents, but

for _, pf := range body.Personality{
    pf.Mutate()
}

does not? Is it that range creates new instances of each item it iterates over? because the struct does in fact mutate but it doesn't persist.

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Stasis
  • 585
  • 1
  • 4
  • 10
  • possible duplicate of [Change values while iterating in golang](http://stackoverflow.com/questions/15945030/change-values-while-iterating-in-golang) – nemo Sep 19 '13 at 21:28
  • 1
    Wasn't really sure where the underlying problem was, so I wasn't fully sure as to what I should've been searching for, that was one of my thoughts though, thanks. – Stasis Sep 19 '13 at 21:31
  • Most of the time staring hard at the [spec](http://golang.org/ref/spec) is enough (eventually the answer will jump you in the face). But I have to admit, this one is a bit tricky. I've updated my answer once again to quote the spec. – nemo Sep 19 '13 at 21:49

2 Answers2

2

The range keyword copies the results of the array, thus making it impossible to alter the contents using the value of range. You have to use the index or a slice of pointers instead of values if you want to alter the original array/slice.

This behaviour is covered by the spec as stated here. The crux is that an assignment line x := a[i] copies the value a[i] to x as it is no pointer. Since range is defined to use a[i], the values are copied.

Community
  • 1
  • 1
nemo
  • 55,207
  • 13
  • 135
  • 135
1

Your second loop is roughly equivalent to:

for x := range body.Personality {
    pf := body.Personality[x]
    pf.Mutate()
}

Since body.Personality is an array of structs, the assignment to pf makes a copy of the struct, and that is what we call Mutate() on.

If you want to range over your array in the way you do in the example, one option would be to make it an array of pointers to structs (i.e. []*PFile). That way the assignment in the loop will just take a pointer to the struct allowing you to modify it.

James Henstridge
  • 42,244
  • 6
  • 132
  • 114