gpt4 book ai didi

for-loop - 在 for 循环中使用指针

转载 作者:IT老高 更新时间:2023-10-28 13:06:19 26 4
gpt4 key购买 nike

我很难理解为什么我的代码在一种状态下存在错误,而在另一种状态下却没有。我已经有一段时间没有介绍指针了,所以我可能已经生疏了!

基本上我有一个我用来在内存中存储对象的存储库结构,它有一个 Store 函数。

type chartsRepository struct {
mtx sync.RWMutex
charts map[ChartName]*Chart
}

func (r *chartsRepository) Store(c *Chart) error {
r.mtx.Lock()
defer r.mtx.Unlock()
r.charts[c.Name] = c
return nil
}

所以它所做的只是设置一个 RW 互斥锁并将指针添加到由标识符引用的映射。

然后我有一个函数,它基本上会遍历这些对象的一部分,将它们全部存储在存储库中。

type service struct {
charts Repository
}

func (svc *service) StoreCharts(arr []Chart) error {
hasError := false
for _, chart := range arr {
err := svc.repo.Store(&chart)
// ... error handling
}
if hasError {
// ... Deals with the error object
return me
}
return nil
}

上面的方法不起作用,起初看起来一切正常,但是在稍后尝试访问数据时, map 中的条目都指向同一个 Chart 对象,尽管有不同的键。

如果我执行以下操作并将指针引用移动到另一个函数,一切都会按预期工作:

func (svc *service) StoreCharts(arr []Chart) error {
// ...
for _, chart := range arr {
err := svc.storeChart(chart)
}
// ...
}

func (svc *service) storeChart(c Chart) error {
return svc.charts.Store(&c)
}

我假设问题是因为循环覆盖了 for 循环中对 chart 的引用,所以指针引用也发生了变化。当指针在独立函数中生成时,该引用永远不会被覆盖。对吗?

我觉得我很愚蠢,但是指针不应该由 &chart 生成并且独立于 chart 引用吗?我还尝试在 for 循环中为指针 p := &chart 创建一个新变量,但这也不起作用。

我应该避免在循环中生成指针吗?

最佳答案

这是因为只有一个循环变量chart,并且在每次迭代中只为其分配一个新值。因此,如果您尝试获取循环变量的地址,那么在每次迭代中它都是相同的,因此您将存储相同的指针,并且指向的对象(循环变量)在每次迭代中被覆盖(并且在循环之后它将保留上次迭代中分配的值)。

这在 Spec: For statements: For statements with range clause: 中有所提及

The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration. If the iteration variables are declared outside the "for" statement, after execution their values will be those of the last iteration.

您的第二个版本有效,因为您将循环变量传递给函数,因此将对其进行复制,然后您存储副本的地址(与循环变量分离)。

你可以在没有函数的情况下达到同样的效果:只需创建一个本地副本并使用它的地址:

for _, chart := range arr {
chart2 := chart
err := svc.repo.Store(&chart2) // Address of the local var
// ... error handling
}

另外请注意,您还可以存储 slice 元素的地址:

for i := range arr {
err := svc.repo.Store(&arr[i]) // Address of the slice element
// ... error handling
}

这样做的缺点是,由于您存储指向 slice 元素的指针,所以只要您保留任何指针, slice 的整个支持数组就必须保存在内存中(数组不能被垃圾收集) .此外,您存储的指针将与 slice 共享相同的 Chart 值,因此如果有人修改传递的 slice 的图表值,则会影响您存储其指针的图表。

查看相关问题:

Golang: Register multiple routes using range for loop slices/map

Why do these two for loop variations give me different behavior?

关于for-loop - 在 for 循环中使用指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48826460/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com