Go map中一个很重要的特性

先看一段代码:

func main() {
        m := make(map[int]string)

        m[1] = "a"
        m[2] = "b"
        m[3] = "c"

        for k, v := range m {
                fmt.Println(k, v)
        }

        fmt.Println("-----------------")

        mm := make(map[int]string)

        mm[1] = "a"
        mm[2] = "b"
        mm[3] = "c"

        for k, v := range mm {
                fmt.Println(k, v)
        }

        fmt.Println("-----------------")

        mmm := make(map[int]string)

        mmm[1] = "a"
        mmm[2] = "b"
        mmm[3] = "c"

        for k, v := range mmm {
                fmt.Println(k, v)
        }
}

 我起初以为三次的输出中,元素的输出顺序都是相同的,可惜,得到的结果如下:

[cobbliu@xxx map]$ go run range.go
1 a
2 b
3 c
-----------------
1 a
2 b
3 c
-----------------
3 c
1 a
2 b

 

对,Go中map的一个很重要的特性就是:当您多次通过range循环来迭代访问map中元素时,尽管您访问的是同一个map,但是访问元素的顺序在前后两次range中是不会完全相同的。当然也不是完全随机的。从Go1开始,Go在range遍历Map中元素的时候,从随机的一个位置开始迭代

为什么要这样做?因为Go的设计者们认为会有一些程序员对同一个map中元素的遍历顺序假设为相同,在这个假设的前提下,会做一些事情(今天的我就是这样,在这个假设的前提下,码了很多字母),他们认为不应该对一个map中的元素的遍历顺序有假设,所以从Go1.0开始,随机化了range map的起始位置。

尽管掉坑里了,但是却使我对Go又多了一层好感,Go设计者在每个细节上都深思熟虑,他们尽量保持了语言的严谨性,创造了完整的辅助工具,对于一些模棱两可的特性,强加了约束,只有这样,才会防止在应用层代码出现诡异的bug,让Go语言使用者们能放心使用它。

尽管现在的Go少了泛型,但是这个特性真的有那么必要么?Go说,至少目前,没有那么必要!