Go Map -- 就要學習 Go 語言

前言

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類型爲stringvalue類型爲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?固然是有爲nilMap:學習

var month map[string]int
fmt.Println(month == nil)    // 輸出:true
複製代碼

對於nilmap是不能存取鍵值對的,不然就會報錯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的零值就是nilMap就是底層Hash表的引用。 Mapkey能夠是內置類型,也能夠是結構類型,只要可使用 == 運算符作比較,均可以做爲key切片函數以及包含切片的結構類型,這些類型因爲具備引用語義,不能做爲key,使用這些類型會形成編譯錯誤:.net

month := map[[]string]int{}
// 編譯錯誤:invalid map key type []string
複製代碼

對於Mapvalue來講,就沒有類型限制,固然也沒有任何理由阻止用戶使用切片做爲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賦值給了名爲slicekey。第二段代碼是第一段代碼的簡寫版本。

如何使用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是不容許重複的。 獲取一個不存在的keyvalue的時候,會返回值類型對應的零值,這個時候,咱們就不知道是存在一個值爲零值的鍵值對仍是鍵值對就根本不存在。好在,Map給咱們提供了方法:

february,exists := m["February"]
fmt.Println(february,exists)   // 輸出:0 false
複製代碼

獲取值的時候多了一個返回值,第一個返回值是value,第二個返回值是boolean類型變量,表示value是否存在。這給咱們判斷一個key是否存在就提供了很大便利。

delete--刪除鍵值對

不像SliceGo爲咱們提供了刪除鍵值對的功能--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
複製代碼

可使用空白操做符_忽略返回的keyvalue。屢次執行代碼的時候,你會發現,返回值的順序有多是不同的,也就是說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拷貝時,mmonth是共享底層數據的,改變其中一方數據,另外一方也會隨之改變。相似,在函數間傳遞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]
複製代碼

上面的代碼,咱們使用rangem的鍵值對循環賦值給了month,而後刪除month其中一個鍵值對,經過打印的結果能夠看出,m沒有改變。這就實現了真正的拷貝。 關於Map的使用就講到這,歡迎你們評論交流!


(全文完)

原創文章,若需轉載請註明出處!
歡迎掃碼關注公衆號「Golang來啦」或者移步 seekload.net ,查看更多精彩文章。

公衆號「Golang來啦」給你準備了一份神祕學習大禮包,後臺回覆【電子書】領取!

公衆號二維碼
相關文章
相關標籤/搜索