Hash
表是一種巧妙而且實用的數據結構,是一個無序的key/value
對的集合,其中全部的key
都是不一樣的,經過給定的key
能夠在常數時間複雜度內檢索、更新或刪除對應的value。Map
實際上是一個Hash表的引用,可以基於鍵快速檢索出數據,鍵就像索引同樣指向與該鍵關聯的值。之後有機會再給你們講Map
底層的東西,教會你們如何使用Map
纔是這一節的重點,記住一點:Map
存儲的是無序的鍵值對集合。golang
make
函數make
能夠建立切片,也能夠用來建立Map
。規則是這樣的:數組
m := make(map[keyType]valueType) 複製代碼
咱們來試着建立:markdown
month := make(map[string]int) month["January"] = 1 month["February"] = 2 month["March"] = 3 複製代碼
第一行代碼,建立了key
類型爲string
,value
類型爲int
的空Map
month
,接着,給month
賦值了三個鍵值對。數據結構
上面的代碼,能夠採用字面量的方式實現:函數
month := map[string]int{"January":1,"February":2,"March":3} // 還能夠寫成這樣 month := map[string]int{ "January":1, "February":2, "March":3, } 複製代碼
使用字面量也能夠建立空Map
,大括號裏面不賦值就能夠了:oop
month := map[string]int{} fmt.Println(month) // 輸出:map[] 複製代碼
有空Map
,是否是有nil
Map
?固然是有爲nil
的Map
:學習
var month map[string]int fmt.Println(month == nil) // 輸出:true 複製代碼
對於nil
的map
是不能存取鍵值對的,不然就會報錯panic: assignment to entry in nil map
。可使用提到的make
函數,爲其初始化:spa
var month map[string]int month = make(map[string]int) month["January"] = 1 fmt.Println(month) // 輸出:map[January:1] 複製代碼
天然能想到,Map
的零值就是nil
,Map
就是底層Hash
表的引用。 Map
的key
能夠是內置類型,也能夠是結構類型,只要可使用 ==
運算符作比較,均可以做爲key
。切片、函數以及包含切片的結構類型,這些類型因爲具備引用語義,不能做爲key
,使用這些類型會形成編譯錯誤:.net
month := map[[]string]int{} // 編譯錯誤:invalid map key type []string 複製代碼
對於Map
的value
來講,就沒有類型限制,固然也沒有任何理由阻止用戶使用切片做爲Map
的值:code
m := map[string][]int{} slice := []int{1,2,3} m["slice"] = slice fmt.Println(m["slice"]) // 或者 slice := []int{1,2,3} m := map[string][]int{"slice":slice} fmt.Println(m["slice"]) 複製代碼
第一段代碼,建立了key
類型爲string
,值爲slice
類型的空Map
,接着將切片slice
賦值給了名爲slice
的key
。第二段代碼是第一段代碼的簡寫版本。
Map
Map
的使用就很簡單了,相似於數組,數組是使用索引,Map
使用key
獲取或修改value
。
m := map[string]int{} m["January"] = 1 // 賦值 fmt.Println(m) // 輸出:map[January:1] m["January"] = 10 //修改 fmt.Println(m) // 輸出:map[January:10] january := m["January"] // 獲取value fmt.Println(january) // 輸出:10 複製代碼
執行修改操做的時候,若是key
已經存在,則新值會覆蓋舊值,上面代碼已經體現出來了,因此key
是不容許重複的。 獲取一個不存在的key
的value
的時候,會返回值類型對應的零值,這個時候,咱們就不知道是存在一個值爲零值的鍵值對仍是鍵值對就根本不存在。好在,Map
給咱們提供了方法:
february,exists := m["February"] fmt.Println(february,exists) // 輸出:0 false 複製代碼
獲取值的時候多了一個返回值,第一個返回值是value
,第二個返回值是boolean
類型變量,表示value
是否存在。這給咱們判斷一個key
是否存在就提供了很大便利。
delete
--刪除鍵值對不像Slice
,Go
爲咱們提供了刪除鍵值對的功能--delete
函數。 函數原型:
func delete(m map[Type]Type1, key Type) 複製代碼
第一個參數是Map
,第二個參數是key
。
m := map[string]int{ "January":1, "February":2, "March":3, } fmt.Println(m) // 輸出:map[March:3 January:1 February:2] delete(m,"January") fmt.Println(m) // 輸出:map[February:2 March:3] 複製代碼
刪除一個不存在的鍵值對時,delete
函數不會報錯,沒任何做用。
Map
Map
無法使用for
循環遍歷,跟數組、切片同樣,可使用range
遍歷。
for key, value := range m { fmt.Println(key, "=>", value) } 複製代碼
輸出:
February => 2 March => 3 January => 1 複製代碼
可使用空白操做符_
忽略返回的key
或value
。屢次執行代碼的時候,你會發現,返回值的順序有多是不同的,也就是說Map
的遍歷是無序的。
len
函數可使用len
函數返回Map中鍵值對的數量:
fmt.Println("len(m) =",len(m)) 複製代碼
Map
是一種引用類型Map
是對底層數據的引用。編寫代碼的過程當中,會涉及到Map
拷貝、函數間傳遞Map
等。跟Slice
相似,Map
指向的底層數據是不會發生copy
的。
m := map[string]int{ "January":1, "February":2, "March":3, } month := m delete(month,"February") fmt.Println(m) fmt.Println(month) 複製代碼
輸出:
map[January:1 March:3] map[January:1 March:3] 複製代碼
上面的代碼,將Map
m
賦值給month
,刪除了month
中的一個鍵值對,m
也發生了改變,說明Map
拷貝時,m
和month
是共享底層數據的,改變其中一方數據,另外一方也會隨之改變。相似,在函數間傳遞Map
時,其實傳遞的是Map
的引用,不會涉及底層數據的拷貝,若是在被調用函數中修改了Map
,在調用函數中也會感知到Map
的變化。 那若是我真想拷貝一個Map
怎麼辦?
month := map[string]int{} m := map[string]int{ "January":1, "February":2, "March":3, } for key,value := range m{ month[key] = value } delete(month,"February") fmt.Println(m) fmt.Println(month) 複製代碼
輸出:
map[January:1 February:2 March:3] map[January:1 March:3] 複製代碼
上面的代碼,咱們使用range
將m
的鍵值對循環賦值給了month
,而後刪除month
其中一個鍵值對,經過打印的結果能夠看出,m
沒有改變。這就實現了真正的拷貝。 關於Map
的使用就講到這,歡迎你們評論交流!
原創文章,若需轉載請註明出處!
歡迎掃碼關注公衆號「Golang來啦」或者移步 seekload.net ,查看更多精彩文章。
公衆號「Golang來啦」給你準備了一份神祕學習大禮包,後臺回覆【電子書】領取!