为啥正常的 for 循环允许为结构字段分配值,而 for range 在 Golang 中不起作用? [复制]
Posted
技术标签:
【中文标题】为啥正常的 for 循环允许为结构字段分配值,而 for range 在 Golang 中不起作用? [复制]【英文标题】:Why does normal for loop allows assigning value to struct fields while for range doesn't work in Golang? [duplicate]为什么正常的 for 循环允许为结构字段分配值,而 for range 在 Golang 中不起作用? [复制] 【发布时间】:2020-08-19 16:13:36 【问题描述】:用于范围:
for _, acc := range accounts
accDetails, _ := repo.GetAccountDets(ctx, acc.number, acc.status)
acc.Details = *accDetails
上面那个不行。
但是,以下工作。
for i:=0; i < len(accounts); i++
accDetails, _ := repo.GetAccountDets(ctx, accounts[i].number, accounts[i].status)
accounts[i].Details = *accDetails
这是为什么呢? 我认为在此处添加帐户结构详细信息没有任何价值
【问题讨论】:
第一个赋值给局部变量acc
。第二个分配给切片元素。 Change values while iterating 会回答你的问题吗?
@CeriseLimón 那么,有没有办法使用 for range 循环进行分配,或者根本没有办法?
for i, acc := range accounts .... accounts[i].Details = *accDetails
@CeriseLimón 你先回答了。如果你把它作为答案,我会选择它。
@sofs1 请注意,以下答案和一些重复项似乎暗示,通过遗漏,不可能在 range
循环中直接使用 value
来修改其内容, 仅当您处理非指针值时,这是正确的。如果您的accounts
slice/array/channel/map 包含指针,您可以通过迭代变量直接修改各个值,而无需使用索引。 play.golang.com/p/3FdQiyylxA6
【参考方案1】:
在for i,v:=range slice ...
形式的for 循环中,变量v
与其循环的元素具有相同的类型,并且每次迭代都将下一项的内容从切片/映射复制到v
。因此,如果v
是一个结构并且您为结构成员分配值,则这些成员永远不会被复制回从中复制它的切片中。
如果切片是指向结构的指针切片,则v
是指向结构的指针的副本,并且您对v
的成员所做的更改将反映在原始切片元素上。
解决此问题的一种方法是使用索引:
for i:=range accounts
accounts[i].Field=value
【讨论】:
【参考方案2】:我想说,这个问题超越了 Golang,它与底层数据结构或容器有关。在第二种情况下,您似乎已经知道容器“len(accounts)”的长度,因此它是一个可以按顺序访问的固定存储。不必总是如此。如果帐户是一个不断增加(或减少)的容器怎么办?你会如何取那个容器的长度。相反,您要问的只是“帐户”中的任何内容都可以给我。你打算怎么做?好吧,您设置了一个虚拟变量,它只允许访问或模仿容器的内容(因此带有它的所有属性或“结构字段”)。另外,它可以在后续代码中抛出,并适当考虑范围,用于“只读”目的。
【讨论】:
【参考方案3】:每当您在 for 循环中初始化变量时,该变量仅在局部范围内限定为 for 循环,在范围内您将在 acc 变量中创建元素的副本
for _, acc := range accounts
accDetails, _ := repo.GetAccountDets(ctx, acc.number, acc.status)
acc.Details = *accDetails
acc 只是 accounts 中元素的本地副本,如果您在 acc 中添加任何内容,它不会影响 accounts 切片。
但在你的另一个例子中..
for i:=0; i < len(accounts); i++
accDetails, _ := repo.GetAccountDets(ctx, accounts[i].number, accounts[i].status)
accounts[i].Details = *accDetails
您没有为帐户中的元素制作本地副本,而是通过 accounts[i] 直接访问它们,它将更新 accounts 切片。
如果您仍想使用范围,那么您可以仅使用索引。
for i := range accounts
accDetails, _ := repo.GetAccountDets(ctx, accounts[i].number, accounts[i].status)
accounts[i].Details = *accDetails
【讨论】:
以上是关于为啥正常的 for 循环允许为结构字段分配值,而 for range 在 Golang 中不起作用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章