Go 学习笔记(12)— 字典map定义、初始化、读取字典、删除字典、清空字典、map 按 key 进行有序遍历
Go 中字典也叫做 map , map 是一種無序的鍵值對的集合。 map 最重要的一點是通過 key 來快速檢索數據, key 類似于索引,指向數據的值。
1. 字典定義
可以使用內建函數 make 也可以使用 map 關鍵字來定義 map:
/* 聲明變量,默認 map 是 nil */
var mapName map[mapKey]mapValue/* 使用 make 函數 */
mapName := make(map[mapKey]mapValue)
這兩者區別在:
-
直接用
var聲明,只是聲明了變量mapName,但是沒有初始化內存,如果直接寫入會導致出現 nil map 繼而導致恐慌(panic)事; -
使用內置函數
make,會聲明并初始化一個哈希映射數據結構,并返回一個指向它的映射值。這是正確的初始化map的方法。
定義一個字典類型變量語法格式有以下多種寫法:
var mapName map[mapKey]dataType
var mapName map[mapKey]dataType = make(map[mapKey]dataType)
var mapName = make(map[mapKey]dataType)
var mapName map[mapKey]dataType = map[mapKey]dataType{}
var mapName = map[mapKey]dataType{}
mapName := map[mapKey]dataType{}
mapName := make(map[mapKey]dataType)
// 創建一個映射,鍵的類型是string,值的類型是int
dict := make(map[string]int) // map 容量使用默認值
dict := make(map[string]int, len) // map 容量使用給定的 len 值// 創建一個映射,鍵和值的類型都是string
// 使用兩個鍵值對初始化映射
dict := map[string]string{"country": "China", "province": "Shaanxi"}
2. 字典初始化
如果不初始化 map ,那么就會創建一個 nil map 。 nil map 不能用來存放鍵值對。
可以通過聲明一個未初始化的映射來創建一個值為 nil 的映射(稱為 nil 映射)。
nil 映射不能用于存儲鍵值對,否則,會產生一個語言運行時錯誤,如下
// 通過聲明映射創建一個nil映射
var book map[string]string
book["author"] = "wohu"Runtime Error:
panic: runtime error: assignment to entry in nil map
但是使用內置函數 make 創建的 map 可以用于存儲鍵值對。
book := make(map[string]string)
book["author"] = "wohu"
fmt.Printf("book is %v\n", book) // book is map[author:wohu]
fmt.Printf("book is %v\n", book["author"]) // book is wohu
或者使用如下賦值
d1 := make(map[string]string)
var d2 = map[string]string{} // 注意:后面帶了個大括號
d1["age"] = "18"
d2["name"] = "wohu"
fmt.Printf("d1 is %v\n", d1) // d1 is map[age:18]
fmt.Printf("d2 is %v\n", d2) // d2 is map[name:wohu]
使用函數 len() 可以獲取 map 中 pair 的數目。
3. 字典鍵類型約束
Go 語言字典的鍵類型不可以是函數類型、字典類型和切片類型。
Go 語言規范規定,在鍵類型的值之間必須可以施加操作符 == 和 != 。換句話說,鍵類型的值必須要支持判等操作。由于函數類型、字典類型和切片類型的值并不支持判等操作,所以字典的鍵類型不能是這些類型。
Go 語言中要求,key 的類型必須支持 == 和 != 兩種比較操作符。而函數類型、map 類型自身,以及切片只支持與 nil 的比較,而不支持同類型兩個變量的比較。
s1 := make([]int, 1)
s2 := make([]int, 2)
f1 := func() {}
f2 := func() {}
m1 := make(map[int]string)
m2 := make(map[int]string)
println(s1 == s2) // 錯誤:invalid operation: s1 == s2 (slice can only be compared to nil)
println(f1 == f2) // 錯誤:invalid operation: f1 == f2 (func can only be compared to nil)
println(m1 == m2) // 錯誤:invalid operation: m1 == m2 (map can only be compared to nil)
所以函數類型、map 類型自身,以及切片類型是不能作為 map 的 key 類型的。
另外,如果鍵的類型是接口類型的,那么鍵值的實際類型也不能是上述三種類型,否則在程序運行過程中會引發 panic(即運行時恐慌)。
4. 遍歷字典
注意:遍歷輸出元素的順序與填充順序無關,不能期望 map 在遍歷時返回某種期望順序的結果。
package mainimport "fmt"func main() {book := make(map[string]string)book["price"] = "100"book["author"] = "wohu"book["language"] = "Chinese"for k := range book { // 迭代 key, 不能保證每次迭代元素的順序fmt.Println(k, "value is ", book[k])}for k, v := range book { // 同時迭代 key 和 valuefmt.Println(k, v)}/*查看元素在集合中是否存在 */published, ok := book["published"] /*如果確定是真實的,則存在,否則不存在 *//*fmt.Println(published) *//*fmt.Println(ok) */if ok {fmt.Println("published is ", published)} else {fmt.Println("published not exist")}
}
運行結果為:
price value is 100
author value is wohu
language value is Chinese
price 100
author wohu
language Chinese
published not exist
讀取字典,就是根據 key 值,在字典中查找 key 對應的 value 值,讀取字典通常有兩種方法,分別是:
// 第一種情況,斷言查詢,推薦使用這種方法
val,ok := map[key]// 第二種情況直接查詢
val := map[key]
上邊兩種讀取字典的方法中,
- 第一種采用斷言的方式,當
ok為true時,表示key存在于字典中,當ok為false時,表示key不存在于字典中; - 第二種情況直接查詢
key值的方式,如果key不在map種時,返回值是字典定義中value的類型默認初始值。如value的類型為int,則默認值為 0,如果value類型是指針,則默認是nil;
5. 刪除 map 元素
Go 語言提供了一個內置函數 delete() ,用于刪除容器內的元素,使用 delete() 內建函數從 map 中刪除一組鍵值對, delete() 函數的格式如下:
delete(map, key)
其中 map 為要刪除的 map 實例, key 為要刪除的 map 中鍵值對的鍵。
package mainimport "fmt"func main() {book := map[string]string{"price": "100","author": "wohu","language": "Chinese", // 數組或者字典在多行編寫時必須要在最后一個元素后面加逗號}
// syntax error: unexpected newline, expecting comma or }for k, v := range book {fmt.Println("k is ", k, ",v is ", v)}delete(book, "author")for k, v := range book {fmt.Println("k is ", k, ",v is ", v)}mapLength := len(book)fmt.Println("book length is ", mapLength)
}
delete 函數是從 map 中刪除鍵的唯一方法。即便傳給 delete 的鍵在 map 中并不存在,delete 函數的執行也不會失敗,更不會拋出運行時的異常。
6. 清空 map
Go 語言中并沒有為 map 提供任何清空所有元素的函數、方法,清空 map 的唯一辦法就是重新 make 一個新的 map ,不用擔心垃圾回收的效率, Go 語言中的并行垃圾回收效率比寫一個清空函數要高效的多。
7. 用切片作為 map 的值
既然一個 key 只能對應一個 value ,而 value 又是一個原始類型,那么如果一個 key 要對應多個值怎么辦?
通過將 value 定義為 []int 類型或者其他類型的切片,就可以優雅的解決這個問題,示例代碼如下所示:
mp1 := make(map[int][]int)
mp2 := make(map[int]*[]int)
8. map 的有序遍歷
8.1 先對key進行排序,再根據 key 進行遍歷
Go中沒有一個專門的方法針對map的key進行排序Go中的map默認是無序的,注意也不是按照添加的順序存放的,你每次遍歷,得到的輸出可能不一樣Go中map的排序,是先將key進行排序,然后根據key值遍歷輸出即可
package mainimport ("fmt""sort"
)func main() {//1.定義一個key打亂的字典person := map[int]string{3: "張學友", 1: "劉德華", 2: "郭富城", 4: "黎明", 5: "我"}//2.定義一個切片s := make([]int, 0, len(person))//3.遍歷map獲取key-->s1中for key := range person {s = append(s, key)}//4.給s進行排序sort.Ints(s)// sort.Strings(a)//5. 遍歷s 來讀取 personfor _, k := range s { // 先下標,再數值fmt.Println(k, person[k])}
}
輸出:
1 劉德華
2 郭富城
3 張學友
4 黎明
5 我
8.2 使用 url.Values{} 進行排序
url.Values{} 引用 Go標準庫 http/url,查看庫,可以看到 url.Values 的定義如下:
type Values map[string][]string
參見:https://blog.csdn.net/wohu1104/article/details/106629308
?
從定義可以看出,本質上 map 的擴展方法。我們常用的有 Set、Add、Del、Encode 等函數。
package mainimport ("fmt""net/url"
)func main() {v := url.Values{}v.Add("1", "一")v.Add("2", "二")v.Add("3", "三")v.Add("4", "四")v.Add("5", "五")fmt.Printf("%#v", v)
}
9. map 變量的傳遞開銷
和切片類型一樣,map 也是引用類型。這就意味著 map 類型變量作為參數被傳遞給函數或方法的時候,實質上傳遞的只是一個“描述符”,而不是整個 map 的數據拷貝,所以這個傳遞的開銷是固定的,而且也很小。
并且,當 map 變量被傳遞到函數或方法內部后,我們在函數內部對 map 類型參數的修改在函數外部也是可見的。
package mainimport "fmt"func foo(m map[string]int) {m["key1"] = 11m["key2"] = 12
}func main() {m := map[string]int{"key1": 1,"key2": 2,}fmt.Println(m) // map[key1:1 key2:2] foo(m)fmt.Println(m) // map[key1:11 key2:12]
}
總結
以上是生活随笔為你收集整理的Go 学习笔记(12)— 字典map定义、初始化、读取字典、删除字典、清空字典、map 按 key 进行有序遍历的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 息字开头的成语有哪些?
- 下一篇: Go 学习笔记(14)— 结构体定义、实