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