如何为Go地图指定指针

时间:2018-02-06 16:47:24

标签: pointers dictionary go

我在分配指向地图的指针时遇到问题。也许这是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"。

3 个答案:

答案 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)