【问题标题】:Does Go (deep) copy keys when inserting into a map?插入地图时,Go(深)复制键吗?
【发布时间】:2016-06-03 15:36:30
【问题描述】:

我有一个带有复杂键的map - 例如,二维数组:

m := make(map[[2][3]int]int)

当我在地图中插入一个新键时,Go 是否会对该键进行深层复制?

a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
m[a] = 1

换句话说,如果我在将数组a用作映射键后更改它,映射是否仍然包含a的旧值?

【问题讨论】:

  • Go 中的数组是按值传递的(与切片相反,切片是按引用传递的),所以这与 a := 1; m[a] = 1 没有什么不同;执行映射分配后,键和变量不相关(除非您更改其中之一,否则它们可能仍然具有相同的值)。

标签: dictionary go key


【解决方案1】:

简短的回答,它被复制了。

按照规范,数组是value types

Go 的数组是值。数组变量表示整个数组;它不是指向第一个数组元素的指针(就像 C 中的情况一样)。这意味着当您分配或传递数组值时,您将复制其内容。 (为了避免复制,您可以将指针传递给数组,但那是指向数组的指针,而不是数组。) https://blog.golang.org/go-slices-usage-and-internals

自己看看:

https://play.golang.org/p/fEUYWwN-pm

package main

import (
    "fmt"
)

func main() {
    m := make(map[[2][3]int]int)
    a := [2][3]int{{1, 2, 3}, {4, 5, 6}}

    fmt.Printf("Pointer to a: %p\n", &a)

    m[a] = 1
    for k, _ := range m {
        fmt.Printf("Pointer to k: %p\n", &k)
    }
}

指针不匹配。

编辑:真正的原因是在插入地图时,键值被复制。或者,您可以继续记住上面的规则:数组是值类型,它们的重用表示一个副本。要么在这里工作。 :)

【讨论】:

    【解决方案2】:

    数组总是按值传递,所以,是的,在这种情况下,Go 会制作密钥的深层副本。

    来自language spec

    必须为键类型的操作数完全定义比较运算符 == 和 !=;因此键类型不能是函数、映射或切片。如果键类型是接口类型,则必须为动态键值定义这些比较运算符;失败将导致运行时恐慌。

    键被复制到地图中。排除 mapslice 作为有效密钥意味着密钥不能更改。请注意,如果您使用指针作为键定义映射类型(例如map[*int]int),go 不会跟随指针,它会直接比较指针。

    【讨论】:

    • 我对这里的“深度”这个词要谨慎一些:将值插入映射会复制键的值,,仅此而已。由于当我们谈论语言原语(赋值运算符,将参数传递给函数)时,Go 中的所有内容都是按值传递/复制的,这就是映射键的值发生的情况。 Go 编译器显式分析用作每个映射键的类型,以捕获使用引用类型的尝试——直接或嵌入到结构类型中。
    • IOW,这样的复制不是“深”或“浅”;它是 Go 规范定义的值的复制。而且由于映射键不能使用具有引用语义的类型,因此复制在其结果中总是碰巧是“深”的,但这并不是说它以某种方式定义是深而不是浅——它只是 Go 中如何传递/复制值的副产品;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 2011-12-25
    • 2019-05-27
    • 1970-01-01
    相关资源
    最近更新 更多