为啥正常的 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 中不起作用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥尽量不要将try…catch写在循环中?

for 循环中,step 步长 有啥作用,为啥要设置 步长

有没有办法使用循环分配 ctypes 结构的字段?

欺骗C编译器将整个结构分配为零,没有for循环[重复]

在 for 循环期间访问嵌套对象 VueJS

为啥 Flask SQL Alchemy 允许保存 None 的主键?