我在分配指向地图的指针时遇到问题。也许这是Go中的一个错误?或许我只是做错了什么。代码也在操场上,https://play.golang.org/p/p0NosPtkptz
这是一些说明问题的超简化代码。我正在创建一个名为collections的对象,其中包含两个集合对象。然后我循环遍历这些集合并将它们分配到地图中,其中地图中的键是集合ID。
package main
import (
"fmt"
)
type collection struct {
ID string
Name string
}
type collections struct {
Collections []collection
}
type cache struct {
Index int
Collections map[string]*collection
}
func main() {
var c cache
c.Collections = make(map[string]*collection)
// Create 2 Collections
var col1, col2 collection
col1.ID = "aa"
col1.Name = "Text A"
col2.ID = "bb"
col2.Name = "Test B"
// Add to Collections
var cols collections
cols.Collections = append(cols.Collections, col1)
cols.Collections = append(cols.Collections, col2)
fmt.Println("DEBUG Collections Type", cols)
i := 0
for k, v := range cols.Collections {
c.Index = i
c.Collections[v.ID] = &v
fmt.Println("DEBUG k", k)
fmt.Println("DEBUG v", v)
i++
}
fmt.Println("Collection 1", c.Collections["aa"].ID)
fmt.Println("Collection 2", c.Collections["bb"].ID)
fmt.Println(c)
}
此游乐场代码的输出如下:
DEBUG Collections Type {[{aa Text A} {bb Test B}]}
DEBUG k 0
DEBUG v {aa Text A}
DEBUG k 1
DEBUG v {bb Test B}
Collection 1 bb
Collection 2 bb
{1 map[aa:0x1040a0f0 bb:0x1040a0f0]}
因此,似乎地图出于某种原因为每个条目获取相同的指针。所有" DEBUG"线条打印出我所期望的。但是,三条印刷线在最后,没有。集合1应该是" aa"不是" bb"。
答案 0 :(得分:5)
当您将&v
放入c.Collections[v.ID]
时,您实际上正在分配循环变量v
的相同地址。
此地址最终保存列表的最后一个值。这就是为什么你获得所有密钥的bb Test B
。
打印这些值,您将看到相同的地址。
fmt.Printf("%p\n", c.Collections["aa"])
fmt.Printf("%p\n", c.Collections["bb"])
通过将其复制到循环范围中的新变量,问题就解决了。循环中的每一步都会将一个新的唯一地址放入缓存中。
for k, v := range cols.Collections {
coll := v
c.Collections[v.ID] = &coll
fmt.Println("DEBUG k", k)
fmt.Println("DEBUG v", v)
i++
}
答案 1 :(得分:3)
不幸的是,第一个答案中的代码有一个错误 - 指向局部变量coll的指针:
for k, v := range cols.Collections {
coll := v
c.Collections[v.ID] = &coll
尝试更改集合的属性值:
cols.Collections[0].Name = "Text C"
fmt.Println("Collection 1", cols.Collections[0].Name)
fmt.Println("Collection 1", c.Collections["aa"].Name)
// Collection 1 Text C
// Collection 1 Text A
但另一个代码将打印预期结果:
for k, v := range cols.Collections {
c.Index = i
p := &cols.Collections[k]
c.Collections[v.ID] = p
....
cols.Collections[0].Name = "Text C"
fmt.Println("Collection 1", cols.Collections[0].Name)
fmt.Println("Collection 1", c.Collections["aa"].Name)
// Collection 1 Text C
// Collection 1 Text C
答案 2 :(得分:0)
关于同一指针的答案是地图包含变量v的地址,但不包含数组项。
const wchar_t*
正确的解决方案是存储指向数组的指针,但不存储值。
for k, v := range cols.Collections {
......
c.Collections[v.ID] = &v
或者获取地图项目的地址(作为答案更高)
type collections struct {
Collections []*collection
}
cols.Collections = append(cols.Collections, &col1)
cols.Collections = append(cols.Collections, &col2)