Golang基礎教程——map使用篇
今天是golang專題的第7篇文章,我們來聊聊golang當中map的用法。
map這個資料結構我們經常使用,儲存的是key-value的鍵值對。在C++/java當中叫做map,在Python中叫做dict。這些資料結構的名稱雖然不經相同,背後的技術支撐也不一定一樣,比如說C++的map是紅黑樹實現的,Java中的hashmap則是通過hash表。但是使用起來的方法都差不多,除了Java是通過get方法獲取鍵值之外,C++、Python和golang都是通過方括號獲取的。
宣告與初始化
golang中的map宣告非常簡單,我們用map關鍵字表示宣告一個map,然後在方括號內填上key的型別,方括號外填上value的型別。
var m map[string] int
這樣我們就宣告好了一個map。
但是要注意,這樣宣告得到的是一個空的map,map的零值是nil,可以理解成空指標。所以我們不能直接去操作這個m,否則會得到一個panic。
panic: assignment to entry in nil map
panic在golang當中表示非常嚴重不可恢復的錯誤,可以恢復的錯誤有些類似於Java或者是其他語言當中的異常,當異常出現的時候,我們可以選擇handle住它們,讓程式不崩潰繼續執行。而那些非常嚴重,無法handle的異常在golang當中稱為panic。
golang當中的異常處理機制和其他語言相差很大,整體的邏輯和核心都不太一樣。當然這個是一個比較大的話題,我們這裡可以簡單將它理解成error就行了。
回到map上來,我們聲明瞭一個map之後,想要使用它還需要對它進行初始化。使用它的方法也很簡單,就是使用make方法創建出一個例項來。它的用法和之前通過make建立元組非常類似:
m = make(map[string] int)
// 我們還可以指定創建出來的map的儲存能力的大小
m = make(map[string] int, 100)
我們也可以在宣告的時候把初始化也寫上:
var m = map[string] int {"abc": 3, "ccd": 4}
當然也可以通過賦值運算子,直接make出一個空的map來:
m := make(map[string] int)
增刪改查
map建立好了當然是要用的,整體使用起來和Python當中的dict比較像,比較簡單直觀,沒有太多彎彎繞的東西。我們一個一個來看,首先是map的新增元素。map的新增元素直接用方括號賦值即可:
m["abc"] = 4
同樣,我們需要保證這裡的m經過初始化,否則也會包nil的panic。如果key值在map當中已經存在,那麼會自動替換掉原本的key。也就是說map的更新和新增元素都是一樣的,都是通過這種方式。如果不存在就是新增,否則則是更新。
刪除元素也很簡單,和Python當中類似,通過delete關鍵字刪除。
delete(m, "abc")
當我們刪除key的時候,如果是其他的語言,我們需要判斷這個key值是否存在,否則的話不能刪除,或者是會引起異常。在golang當中並不會,對這點做了優化。如果要刪除的key值原本就不在map當中,那麼當我們呼叫了delete之後,什麼也不會發生。但是有一點,必須要保證傳入的map不為nil,否則也會引起panic。
最後,我們看下元素的查詢。對於Java和Python來說我們都是通過一些判斷語句來進行判斷的,比如java的話是containsKey,Python的話用in操作符。在golang當中我們則是直接通過方括號進行查詢,那麼這就有了一個問題,如果key不在其中怎麼辦?
如果是其他語言,我們直接訪問一個不存在的key是會丟擲異常的,但是在golang當中不會觸發panic,因為它會額外返回一個bool型別的元素表示元素是否查詢到。所以我們可以同時用兩個變數去接收,如果第二個變數為True的話,就說明查詢成功了。
進一步,我們還可以將這個邏輯和if的初始化操作合在一起:
if val, ok := m["1234"]; ok {
fmt.Println(val)
}
這裡的ok就表示查詢是否成功,這也是golang當中map查詢的慣用寫法。
最後, 我們看一個實際運用map的例子,通過map來生成統計字串當中單詞數量的wordCount:
package main
import (
"golang.org/x/tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
cnt := make(map[string]int)
// 通過Split方法拆分字串
for _, str:= range strings.Split(s){
// 直接++即可,golang會自動填充
cnt[str]++
}
return cnt
}
func main() {
wc.Test(WordCount)
}
總結
到這裡,關於golang當中map的使用就算是介紹完了。我們可以發現,map一如既往地體現了golang語法精簡的特點。比如通過返回error的操作省略了判斷元素是否存在map當中的操作,剛開始的時候會覺得有些不太適應,但是接觸多了之後,會發現這些都是有套路的。golang的套路就是精簡,能省就省,能簡單絕不復雜。
這一點不僅在map上體現,在其他特性上也是一樣。在後續的內容當中,我們還會繼續感知這一點。
如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。