英文:
Go: Can you use range with a slice but get references? (iteration)
问题
假设我想要更改数组中所有对象的值。
我更喜欢使用范围语法,而不仅仅是命名的for循环。
所以我尝试了以下代码:
type Account struct {
balance int
}
type AccountList []Account
var accounts AccountList
...
....
// 初始化余额
for _,a := range( accounts ) {
a.balance = 100
}
这段代码不起作用,因为a是AccountList中条目的副本,因此我们只更新了副本。
以下代码可以正常工作:
for a := range( accounts ) {
accounts[a].balance = 100
}
但是这段代码在for循环内部有额外的查找操作。
有没有一种方法可以创建一个迭代器,以获取AccountList中结构体的引用?
英文:
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?
答案1
得分: 4
只需将AccountList设置为[]*Account。然后,您将在范围内获得每个Account的指针。
英文:
Just let the AccountList be []*Account. Then you'll get pointers to each Account inside the range.
答案2
得分: 4
问题在于使用第一个for/range循环时,你通过变量a
按值获取了结构体。你使用的第二个for/range循环解决了这个问题,通过直接访问切片中的内存。
然而,你错误地声称第二个循环中存在一个“额外”的查找。循环条件只是检查切片的长度,并递增一个计数器直到达到末尾。然后,accounts[a]
表达式将实际执行数组查找并直接操作内存。如果有什么不同的话,第二个循环会产生更少的指令,因为它不会首先按值将结构体的内容复制到变量中。
我认为你担心的是每次都要引用accounts[i]
。如果你想在for循环中对Account执行多个操作,我认为最好的解决方法是这样的:
for i := range accounts {
a := &accounts[i]
a.balance = 100
// 进一步操作账户A...
}
另一个可能的解决方案,就像Mue建议的那样,是简单地让切片持有指针。无论你是在C还是Go中,这两种方式都有各自的优势。Go只是有一点更多的语法糖。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论