先看一段代碼:
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說,至少目前,沒有那么必要!