map字典
golang的map實現並不是像c++一樣使用紅黑樹,而是使用了hashmap,用陣列來實現。
map 是字典的概念,它的格為 “map[keyType]valueType” 。 map 的讀取和設定也類似 slice 一樣,通過 key 來操作,只是 slice 的index 只能是`int`型別,而 map 多了很多型別,可以是 int ,可以是 string及所有完全定義了 == 與 != 操作的型別。
// 1. 宣告 var m map[string]int
// 2. 初始化,宣告之後必須初始化才能使用,向未初始化的map賦值引起 panic: assign to entry in nil map.
m = make(map[string]int)
m = map[string]int{}
// 1&2. 宣告並初始化
m := make(map[string]int)
m := map[string]int{}
// 3. 增刪改查
m["route"] = 66
delete(m, "route") // 如果key不存在什麼都不做
i := m["route"] // 三種查詢方式,如果key不存在返回value型別的零值
i, ok := m["route"]
_, ok := m["route"]
// 4. 迭代(順序不確定 )
for k, v := range m {
use(k, v)
}
// 5. 有序迭代
import "sort"
var keys []string
for k, _ := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
use(k, m[k]
}
那為什麼golang的map是安全的呢,從原始碼來看,golang的map使用了桶的概念,元素是被hash到桶儲存,每個桶預設是儲存八個k,v,而且在頭部有一個uint8 tophash[8]的結構,儲存每個key的高八位(即hash(key) » (64 - 8)),如果該位置未被放置元素,則有一個特殊的標誌Empty。在插入刪除的時候,首先會比較該uint8跟hash(key)是否相等。當然,桶還利用了overflow指標,可以無限的增長,類似連結串列。所以,for迴圈其實是對每個桶進行迭代,判斷每個uint8位置,刪除操作也並不是實際的memset,而是把對應的tophash的位置置為Empty.因此,在迭代golang的map過程中,使用delete是安全的。