为什么不能将go slice(这是GO数组的实现)用作GO MAPS中的键,几乎可以用作键的方式?
这是https://groups.google.com/forum/# !! Topic/golang-nuts/zylx6sr4f8y:
一个原因是数组是值类型。如果
a0
是[N]int
(一个 阵列)然后做a1 := a0 a1[0] = 0
根本不会影响
a0[0]
。相比,切片是指基础数组。复制切片 值是O(1)而不是O(长度)。如果
s0
是[]int
(切片) 然后做s1 := s0 s1[0] = 0
会影响
s0[0]
是什么。http://play.golang.org/p/tvkntislo8
地图密钥需要一些平等概念。对于数组,这简直就是 元素平等。对于切片,有多种方法 定义平等:一个是元素平等,另一个是指 同一数组备份商店。此外,图插入确实需要 制作(昂贵的)整个备用阵列的副本?复制会 可能不那么令人惊讶,但它与什么不一致 作业做。
此代码段应该打印什么?
m := make(map[[]int]bool) s0 := []int{6, 7, 8} s1 := []int{6, 7, 8} s2 := s0 m[s0] = true s2[0] = 9 println(m[s0]) println(m[s1]) println(m[s2])
不同的程序员可以有不同的期望。避免 混乱,我们只是决定不允许切片作为地图键 现在。
回答确切的"为什么不能?":
规格:地图类型:
比较运算符==和!=必须为密钥类型的操作数充分定义;因此,密钥类型不得是函数,地图或 slice 。
规格不允许在未定义比较的情况下进行关键类型。规格:比较操作员还确认了这一点:
slice ,地图和功能值是不可比较。
有关推理,请参见Smarx的答案(引用Nigel Tao的答案)。并继续阅读。
GO的地图使用Hashmap实现。通常,(无论编程语言如何)突变被用作hashmap中键的值可能导致不确定的(或意外的最少)行为。通常,键的标签用于指定放置值(键值对)的桶。如果密钥更改并要求该密钥的关联值,则实现可能会以错误的存储键看(因此报告它找不到它),因为更改的键值很可能会产生不同的hashcode不同的桶。
在Go Slices中只是对基础数组连续部分的描述符,而分配切片值仅复制这些描述符。因此,使用切片作为钥匙,您会期望地图实现仅复制此切片标头(这是指向基础数组中第一个引用元素的指针,长度和容量)。它只有在哈希(Hash Comptation)和平等性使用这3个元素时才起作用,而其他任何内容都没有,但对我们(人类,程序员)来说,切片意味着可以通过slice标头访问的元素 - 也可以修改(引起上面描述的问题)。
如果映射允许切片作为密钥,则可以正常运行,只要修改任何切片的切片(用作键),它就必须更新其内部状态和数据结构预期。
数组在这方面很酷:一个数组表示其所有元素;复制阵列副本所有元素,并将比较定义为:
如果数组元素类型的值是可比的,则数组值是可比的。如果它们的相应元素相等,则两个数组值相等。
,如果您修改了以前用作键的数组的元素:不是问题,因为新数组(带有修改的元素)不等于在地图中存储和使用的原始内容,因此请查询与修改数组的关联值将合理地产生任何结果,并且使用未修改的原始数组的查询将适当地给您以前存储的值。