dictionary - 通过指针的指针更新结构不起作用
问题描述
好的,对于一些简化的设置,在这个例子中我们有三个 structs ,comp
看起来有点像这样:agg
cache
type comp struct {
id uint64
val float64
}
type agg struct {
id uint64
vals []*comp
}
type cache struct {
compMtx sync.RWMutex
comps map[uint64]*comp
aggMtx sync.RWMutex
aggs map[uint64]*agg
}
其中cache
具有以下添加新comp
值的功能,在更新的情况下似乎不起作用:
func (c *cache) NewComp(cpNew *comp) {
compMtx.Lock()
defer compMtx.Unlock()
cpOld, ok := c.comps[cpNew.id]
if ok { // update
addr := &cpOld // this is of type **comp
*addr = cpNew
} else { // new value
c.comps[cpNew.id] = cpNew
}
}
这种方法背后的思想是,通过改变指针指向的位置,我们可以确保comp
指针agg.vals
始终指向给定comp
对象的最新迭代。
至于这种方法背后的原因,遍历整个agg.vals
数组以查找给定comp
对象的索引将 a)由于数组(相当大)的大小而在计算上是昂贵的,并且 b)需要agg
通过一个锁定internalsync.Mutex
在搜索期间阻止不同的线程访问对象,这两者都是不可取的。此外假设制作agg.value
地图以便于轻松更新是不可能的。
但是由于NewComp
上面的实现不起作用,我的问题是上面的函数是否有任何明显的错误,或者我在这里的思考中是否犯了一些基本错误?
由于这可能会有所帮助,这里还有一个示例,其中通过指针的指针进行的更新按预期工作:
type wrks struct {
id uint64
val1 *comp
val2 *comp
}
func compute() *comp {...}
func updateComp(c **comp) {
*c = compute()
}
func processObj(o *obj) {
updateComp(&o.val1)
updateComp(&o.val2)
}
我看不出两者之间的根本区别,但此时我可能已经盯着这个看太久了。
解决方案
您将指针存储在映射中,因此当您从中获取指针时,只需修改指向的值,分配给指向的值:
cpOld, ok := c.comps[cpNew.id]
if ok { // update
*cpOld = *cpNew
} else { // new value
c.comps[cpNew.id] = cpNew
}
请参阅Go Playground上的一个简化示例,该示例显示了此方法。
您的原始代码不起作用,因为cpOld
它是一个指针,但它是存储在地图中的指针的副本。如果您修改此cpOld
变量的值,则不会影响地图中存储的值。您不能更改地图中的值,只能在其中重新分配/存储新值。
您应该记住一件事:cpNew
传递给的指针NewComp()
在更新后将不会“有用”,因为我们没有使用指针,我们只是使用指向的值来更新映射已经指向的值(a值存储在地图中)。如果您希望指针继续指向相同的值,您别无选择,只能将该指针存储在映射中,就像它是新的一样:
cpOld := c.comps[cpNew.id] = cpNew
请参阅相关问题:如何在 Go 中更新地图值
推荐阅读
- powershell - 是否可以使用 SecureCRT 以管理员身份连接 powershell?
- reactjs - jsPDF addImage 输出灰色方块
- ofbiz - 使用 OFBIZ 中的图表从 Birt 报告生成 PDF
- ignite - 点燃瘦客户端 - 仅从扫描查询中获取键而不是值
- c# - 添加对何时为特定对象添加数据的限制
- docker - 无法访问 docker 容器 alpine 基础映像上的网页
- jobs - 在 Azure Databricks 环境中初始化集群需要更长的时间并且有时会引发错误
- solana - Solana 链上查询
- html - 仅单击一个子菜单时如何防止引导程序折叠所有子菜单?
- python - 如何根据列名合并数据框?