Jeroen Dirks
Jeroen Dirks

Reputation: 7877

Go: Can you use range with a slice but get references? (iteration)

Say I want to change a value for all objects in an array. I like the range syntax a lot more than just named for loops.

So I tried:

type Account struct {
   balance int
}
type AccountList []Account
var accounts AccountList
...
....
// to init balances
for _,a := range( accounts ) {
    a.balance = 100
}

That did not work since a is a copy of the entries from the AccountList and we are thus updating the copy only.

This does work as I need it to:

for a := range( accounts ) {
  accounts[a].balance = 100
}

But that code has an extra lookup inside the for loop.

Is there a way to do an iterator that gets references to the structs in the AccountList?

Upvotes: 7

Views: 1630

Answers (2)

Roxy Light
Roxy Light

Reputation: 5147

The problem is that by using your first for/range loop, you are getting the struct by-value in the variable a. The second for/range loop you used solves the problem by accessing the memory in the slice directly.

However, you are incorrect in stating that there is an "extra" lookup taking place inside the second for loop. The loop condition is merely going to examine the length of the slice and increment a counter until it hits the end. The accounts[a] expression will then actually perform an array lookup and manipulate the memory directly. If anything, the second for loop translates to less instructions because it isn't copying the contents of the struct by-value into a variable first.

What I think you are worried about is having to reference accounts[i] every time. If you want to perform multiple manipulations on the Account inside the for loop, I think the best way to solve it would be like this:

for i := range accounts {
    a := &accounts[i]
    a.balance = 100
    // manipulate account A further...
}

The other possible solution, as Mue suggested, is to simply have the slice hold pointers. There are advantages to either of the ways of doing this, but the dilemma is the same regardless of whether you are in C or Go. Go just has a little more syntactic sugar.

Upvotes: 8

themue
themue

Reputation: 7850

Just let the AccountList be []*Account. Then you'll get pointers to each Account inside the range.

Upvotes: 3

Related Questions