Do Go实现存储地图的长度?

时间:2015-08-01 04:43:56

标签: dictionary go

map是否将其长度存储在某处或是否在每次调用len(my_map)时进行计算?

语言规范为地图显示了这一点,这实际上没有帮助:

  

map元素的数量称为其长度。对于地图m,可以使用内置函数len发现它,并且可以在执行期间更改。可以在执行期间使用赋值添加元素,并使用索引表达式检索元素;可以使用delete内置函数删除它们。

在“长度和容量”部分下,我们看到:

  

如果len(s)s常量,则表达式string是常量。如果len(s)的类型为cap(s)sarray且表达式为{{1},则表达式pointerarray是常量不包含通道接收或(非常量)函数调用;在这种情况下,不评估s。否则,slen的调用不会保持不变,并会评估cap

因此,它告诉我们s不是常量并且已经过评估,但它没有说明它是否像s类型一样被查找为存储值。

1 个答案:

答案 0 :(得分:13)

我没有查看消息来源,但我写了一个快速的基准。

它测试了4张地图,其中2根是int,2则是string

var m1 = make(map[int]int)    // key is of type int, len(m1) = 10
var m2 = make(map[int]int)    // key is of type int, len(m2) = 1000000
var s1 = make(map[string]int) // key is of type string, len(s1) = 10
var s2 = make(map[string]int) // key is of type string, len(s2) = 1000000

“小”地图有10个元素,“大”地图有百万个元素。地图填充如下:

func init() {
    for i := 0; i < 10; i++ {
        m1[i] = i
        s1[strconv.Itoa(i)] = i
    }
    for i := 0; i < 1000000; i++ {
        m2[i] = i
        s2[strconv.Itoa(i)] = i
    }
}

基准测试功能如下:

func BenchmarkSmallIntMap(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for j := 0; j < 1000; j++ {
            _ = len(m1) + len(m1) + len(m1) + len(m1) + len(m1) + len(m1)
        }
    }
}

其他所有内容都相似,但显然使用m2s1s2。结果如下:

BenchmarkSmallIntMap     1000000              2085 ns/op
BenchmarkLargeIntMap     1000000              2087 ns/op
BenchmarkSmallStringMap  1000000              2087 ns/op
BenchmarkLargeStringMap  1000000              2086 ns/op

所有都是相同的,几乎可以说len(m)的执行时间不依赖于地图大小(键值对的数量),这表明存储地图长度并且在被叫时不被“计算”。

如果有兴趣,这里是完整的测试来源:Go Playground

twotwotwo检查sources存储长度