前言 本文主要紀錄 Go 語言中的 Map
Golang 中的 map map 為 Golang 中鍵值對(key-value )的資料結構,左側為 key ,右側為 value,有以下幾個特性:
排列無一定順序
key 在 map 是唯一的,而 value 可能不是
適合用在: 基於 key 快速尋找、取得和刪除資料
map 的零值為 nil
相關操作 宣告 map 語法結構
1 var m map [KeyType]ValueType
說明
KeyType : 鍵的資料型別
ValueType : 值的資料型別
map 的零值 前面提到過 map 的零值為 nil,而值為 nil 的 map 沒有 key,來看以下範例:
1 2 3 4 5 6 7 var m map [string ]int fmt.Println(m)if m == nil { fmt.Println("m is nil" ) }
輸出
若將 key 加到值為 nil 的 map 的會導致 Golang 於執行時期發生錯誤
1 2 3 var m map [string ]int m["hello" ] = 1
彙報如同下方的錯誤
1 panic : assignment to entry in nil map
初始化 map 實例 使用 make() 函示即可建一個 map 實例,該函式會回傳已初始化及可以使用的 map 值 語法結構
1 make (map [KeyType]KeyType)
來看範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 m := make (map [string ]int ) fmt.Println(m) fmt.Println(len (m)) if m == nil { fmt.Println("m is nil" ) } else { fmt.Println("m is not nil" ) } m["hello" ] = 1 fmt.Println(m) fmt.Println(m["hello" ])
輸出結果為:
1 2 3 4 5 map []0 m is not nil map [hello:1 ]1
初始化 map 時給值 遇到已知 map 中會有 key-value 的情形,可以如下方範例建立 map
1 2 3 4 5 6 7 8 9 var m = map [string ]int { "one" : 1 , "two" : 2 , "three" : 3 , "four" : 4 , "five" : 5 , } fmt.Println(m)
注意:
最後一個必需加上逗號 ,否則將出現編譯錯誤 若是最後一個 key-value 項目後不換行,最後一個就不需要逗號
1 2 t := map [string ]int {"t1" : 1 , "t2" : 2 } fmt.Println(t)
可用來做為 key 的值 Golang 裡可用來做為 key 的值,須為 comparable 型態,如:數值、字串、布林值、channel、pointer、struct、interface 等等,注意:函式、切片(slice)、map 皆不能做為 key
map 為參考型別 若將 map 指派給新變數時,它們皆參考同樣底層的資料結構
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 mm1 := map [string ]int { "one" : 1 , "two" : 2 , "three" : 3 , "four" : 4 , "five" : 5 , } mm2 := mm1 fmt.Println("mm1 = " , mm1) fmt.Println("m2 = " , mm2) fmt.Println("========" ) mm2["ten" ] = 10 fmt.Println("mm1 = " , mm1) fmt.Println("mm2 = " , mm2)
由下述結果可知,將 mm1 賦值給 mm2 後(mm2 := mm1),只改變 mm2 的 key 對應的值,mm1 相同名稱的 key 也跟著改變 -> 一個改變,另一個也相應的改變
1 2 3 4 5 mm1 = map [five:5 four:4 one:1 three:3 two:2 ] mm2 = map [five:5 four:4 one:1 three:3 two:2 ] ======== mm1 = map [five:5 four:4 one:1 ten:10 three:3 two:2 ] mm2 = map [five:5 four:4 one:1 ten:10 three:3 two:2
key-value 的操作 map 存取 寫過 Python 的人對這個用法: m[key] 一點也不陌生,類似於對 dictionary 的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var person = make (map [string ]string ) person["name" ] = "Tom" person["gender" ] = "male" person["country" ] = "ROC" fmt.Println(person) fmt.Println(person["name" ]) person["name" ] = "Jack" fmt.Println(person)
取得未分派給 map 中 key 若分派得 key 尚未存於 map ,則會得到 map 值型別的零值
1 2 city := person["city" ] fmt.Println(city)
在上面的範例中,由於名為 city 的 key 不存於 map 中,得到 map 值型別對應的零值。由於 map 值的型別是 string,因此輸出的結果為 ""
所以在Golang 中即便 key 不存於 map 裡,也不會出現執行時期錯誤
如何檢查 map 中不存在的 key? 其實使用 mapName[key] 時,除了得到分派給特定的 key 對應的值,同時回傳一個布林值。換句話說,若是沒有該 key ,即回傳該值的資料型別的零值,第二個是布林值,指出鍵是否存在。 拿上述範例來看
1 2 3 4 5 name, ok := person["name" ] fmt.Println("name: " , name, ok) city, ok := person["city" ] fmt.Println("city: " , city, ok)
回傳結果
1 2 name: Jennifer true city: false
從結果可知,若該 key 是存在的,回傳布林值為 true,反之則為 false。 藉由上述方法,我們也能單純做檢查 key 是否存在,使用 _ 略過回傳的值
1 2 3 4 5 6 7 8 9 10 11 if _, ok := person["name" ]; ok { fmt.Println("Name existed" ) } else { fmt.Println("No name" ) }if _, ok := person["city" ]; ok { fmt.Println("City existed" ) } else { fmt.Println("No city" ) }
結果
刪除 map 中的 key 使用內建函式 delete() 刪除 map 中的 key,而函式不會回傳任何值。若該 key 不存於 map中,也不會執行任何操作。
語法結構
範例
1 2 3 4 5 6 7 8 9 10 person := map [string ]string { "name" : "Tom" , "gender" : "male" , "country" : "ROC" , } fmt.Println(person) delete (person, "gender" ) fmt.Println(person)
迭代 map 透過 for 迴圈搭配 range 迭代 map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 person := map [string ]string { "name" : "Tom" , "gender" : "male" , "country" : "ROC" , } fmt.Println("====== 迭代 key, value ======" )for k, v := range person { fmt.Println("key: " , k) fmt.Println("value: " , v) } fmt.Println("====== 只迭代 key ======" )for k := range person { fmt.Println("key: " , k) } fmt.Println("====== 只迭代 value ======" )for _, v := range person { fmt.Println("value: " , v) }
結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ====== 迭代 key, value ====== key: name value: Tom key: gender value: male key: country value: ROC ====== 只迭代 key ====== key: name key: gender key: country ====== 只迭代 value ====== value: Tom value: male value: ROC
排序 map 本文開頭有提及 map 排列無一定順序 ,若要將結果做排序,必須另外處理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 person := map [string ]string { "name" : "Tom" , "gender" : "male" , "country" : "ROC" , } keys := make ([]string , 0 , len (person))for key := range person { keys = append (keys, key) } sort.Strings(keys)for _, key := range keys { fmt.Printf("%s : %q\n" , key, person[key]) }
結果
1 2 3 country : "ROC" gender : "male" name : "Tom"