Go語言基礎教程——map篇

本文始發於個人公衆號:TechFlow,原創不易,求個關注


今天是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上體現,在其他特性上也是一樣。在後續的內容當中,我們還會繼續感知這一點。

如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章