Go語言學(xué)習(xí)之映射(map)的用法詳解
1. 什么是 map
Map 是一種無序的鍵值對(duì)的集合。Map 最重要的一點(diǎn)是通過 key 來快速檢索數(shù)據(jù),key 類似于索引,指向數(shù)據(jù)的值
Map 是無序的,我們無法決定它的返回順序,這是因?yàn)?Map 是使用 hash 表來實(shí)現(xiàn)的
Map 是引用類型,必須初始化才能使用。其中,key的類型除了切片等引用類型,其他類型都可以;而value則可使用所有類型的值
2. 創(chuàng)建 map
可以通過make()創(chuàng)建map,它會(huì)先創(chuàng)建好底層數(shù)據(jù)結(jié)構(gòu),然后再創(chuàng)建map,并讓map指向底層數(shù)據(jù)結(jié)構(gòu)
my_map := make(map[string]int)
[string]表示map的key的數(shù)據(jù)類型
int表示key對(duì)應(yīng)的值
直接通過大括號(hào)創(chuàng)建并初始化賦值:
// 空map my_map := map[string]string{} // 初始化賦值 my_map := map[string]string{"Red": "#da1337","Orange": '#e95a22"} // 格式化賦值 my_map := map[string]int{ "Java":11, "Perl":8, "Python":13, // 注意結(jié)尾的逗號(hào)不能少 }
注意:
其中map的key可以是任意內(nèi)置的數(shù)據(jù)類型(如int),或者其它可以通過 == 進(jìn)行等值比較的數(shù)據(jù)類型,如interface和指針可以,slice、數(shù)組、map、struct類型都不能作為key ,并且key必須唯一。
但value基本可以是任意類型,例如嵌套一個(gè)slice到map中:
my_map := map[string][]int{}
3. 訪問 map
訪問map中的元素時(shí),指定它的key即可,注意string類型的key必須加上引號(hào):
package main import "fmt" func main() { my_map := map[string]int{ "1": 10, "2": 20, "3": 30, "4": 40, } //訪問 fmt.Println(my_map["1"]) fmt.Println(my_map) fmt.Println("") //賦值已有的key & value my_map["2"] = 50 fmt.Println(my_map["2"]) fmt.Println(my_map) fmt.Println("") //賦值新的key&value my_map["5"] = 66 fmt.Println(my_map["5"]) fmt.Println(my_map) }
輸出結(jié)果
10
map[1:10 2:20 3:30 4:40]
50
map[1:10 2:50 3:30 4:40]
66
map[1:10 2:50 3:30 4:40 5:66]
4. nil map和空map
空map是不做任何賦值的map:
// 空map package main import "fmt" func main() { my_map := map[string]string{} fmt.Println(my_map) }
輸出結(jié)果
map[]
nil map,它將不會(huì)做任何初始化,不會(huì)指向任何數(shù)據(jù)結(jié)構(gòu):
// nil map var my_map map[string]string
nil map和empty map的關(guān)系,就像nil slice和empty slice一樣,兩者都是空對(duì)象,未存儲(chǔ)任何數(shù)據(jù),但前者不指向底層數(shù)據(jù)結(jié)構(gòu),后者指向底層數(shù)據(jù)結(jié)構(gòu),只不過指向的底層對(duì)象是空對(duì)象。
使用println輸出看下即可知道:
package main func main() { var nil_map map[string]string println(nil_map) emp_map := map[string]string{} println(emp_map) }
輸出結(jié)果:
0x0
0xc04204de38
所以,map類型實(shí)際上就是一個(gè)指針。
5. map中元素的返回值
當(dāng)訪問map中某個(gè)元素的時(shí)候,有兩種返回值的格式:
value := my_map["key"] value,exists := my_map["key"]
第一種很好理解,就是檢索map中key對(duì)應(yīng)的value值。如果key不存在,則value返回值對(duì)應(yīng)數(shù)據(jù)類型的0。例如int為數(shù)值0,布爾為false,字符串為空""。
第二種不僅返回key對(duì)應(yīng)的值,還根據(jù)key是否存在返回一個(gè)布爾值賦值給exists變量。所以,當(dāng)key存在時(shí),value為對(duì)應(yīng)的值,exists為true;當(dāng)key不存在,value為0(同樣是各數(shù)據(jù)類型所代表的0),exists為false。
看下例子:
package main import "fmt" func main() { my_map := map[string]int{ "1": 10, "2": 20, "3": 30, "4": 40, } a := my_map["1"] b, exists1 := my_map["2"] c, exists2 := my_map["5"] fmt.Println(a) fmt.Println(b, exists1) fmt.Println(c, exists2) }
上面將輸出如下結(jié)果:
10
20 true
0 false
在Go中設(shè)置類似于這種多個(gè)返回值的情況很多,即便是自己編寫函數(shù)也會(huì)經(jīng)常設(shè)置它的exists屬性。
6. len()和delete()
len()函數(shù)用于獲取map中元素的個(gè)數(shù),即有多個(gè)少key。delete()用于刪除map中的某個(gè)key。
package main import "fmt" func main() { my_map := map[string]int{ "1": 10, "2": 20, "3": 30, "4": 40, } fmt.Printf("刪除前長(zhǎng)度為%d\n", len(my_map)) delete(my_map, "1") fmt.Printf("刪除后長(zhǎng)度為%d", len(my_map)) }
輸出結(jié)果如下
刪除前長(zhǎng)度為4
刪除后長(zhǎng)度為3
7. 測(cè)試map中元素是否存在
兩種方式可以測(cè)試map中是否存在某個(gè)key:
① 根據(jù)map元素的第二個(gè)返回值來判斷
② 根據(jù)返回的value是否為0(不同數(shù)據(jù)類型的0不同)來判斷
方式一:直接訪問map中的該元素,將其賦值給兩個(gè)變量,第二個(gè)變量就是元素是否存在的修飾變量。
package main import "fmt" func main() { my_map := map[string]int{ "1": 10, "2": 20, "3": 30, "4": 40, } //方法1 /* value, exists := my_map["1"] if exists { fmt.Println("存在", value) } */ //方法2 if value, exists := my_map["1"]; exists { fmt.Printf("值存在, value=%d", value) } }
輸出結(jié)果如下
值存在, value=10
方式二:根據(jù)map元素返回的value判斷。因?yàn)樵搈ap中的value部分是int類型,所以它的0是數(shù)值的0。
package main import "fmt" func main() { my_map := map[string]int{ "1": 10, "2": 20, "3": 30, "4": 40, } value := my_map["5"] if value == 0 { fmt.Println("不存在") } }
輸出結(jié)果如下
不存在
如果map的value數(shù)據(jù)類型是string,則判斷是否為空:
package main import "fmt" func main() { my_map := map[string]string{ "1": "book", "2": "games", "3": "computer", } value := my_map["5"] if value == "" { fmt.Println("不存在") } }
輸出結(jié)果如下
不存在
由于map中的value有可能本身是存在的,但它的值為0,這時(shí)就會(huì)出現(xiàn)誤判斷。例如下面的"3",它已經(jīng)存在,但它對(duì)應(yīng)的值為0
package main import "fmt" func main() { my_map := map[string]int{ "1": 22, "2": 11, "3": 0, } value := my_map["3"] if value == 0 { fmt.Println("不存在") } }
輸出結(jié)果如下
不存在
所以,應(yīng)當(dāng)使用第一種方式進(jìn)行判斷元素是否存在。
8. 迭代遍歷 map
因?yàn)閙ap是key/value類型的數(shù)據(jù)結(jié)構(gòu),key就是map的index,所以range關(guān)鍵字對(duì)map操作時(shí),將返回key和value。
package main import "fmt" func main() { my_map := map[string]int{ "1": 22, "2": 11, "3": 0, "4": 55, "5": 66, } for k, v := range my_map { fmt.Printf("key=%s, value=%d\n", k, v) } }
輸出結(jié)果如下
key=1, value=22
key=2, value=11
key=3, value=0
key=4, value=55
key=5, value=66
如果range迭代map時(shí),只給一個(gè)返回值,則表示迭代map的key:
package main import "fmt" func main() { my_map := map[string]int{ "1": 22, "2": 11, "3": 0, "4": 55, "5": 66, } for key := range my_map { fmt.Println("key=", key) } }
輸出結(jié)果
key= 1
key= 2
key= 3
key= 4
key= 5
9. 獲取map中所有的key
Go中沒有提供直接獲取map所有key的函數(shù)。所以,只能自己寫,方式很簡(jiǎn)單,range遍歷map,將遍歷到的key放進(jìn)一個(gè)slice中保存起來。
package main import "fmt" func main() { my_map := map[string]int{ "Java": 11, "Perl": 8, "Python": 13, "Shell": 23, } // 保存map中key的slice // slice類型要和map的key類型一致 keys := make([]string,0,len(my_map)) // 將map中的key遍歷到keys中 for map_key,_ := range my_map { keys = append(keys,map_key) } fmt.Println(keys) }
注意上面聲明的slice中要限制長(zhǎng)度為0,否則聲明為長(zhǎng)度4、容量4的slice,而這4個(gè)元素都是空值,而且后面append()會(huì)直接對(duì)slice進(jìn)行一次擴(kuò)容,導(dǎo)致append()后的slice長(zhǎng)度為map長(zhǎng)度的2倍,前一半為空,后一般才是map中的key。
10. 傳遞map給函數(shù)
map是一種指針,所以將map傳遞給函數(shù),僅僅只是復(fù)制這個(gè)指針,所以函數(shù)內(nèi)部對(duì)map的操作會(huì)直接修改外部的map。
例如,test()用于給map的key對(duì)應(yīng)的值加1。
package main import "fmt" func main() { my_map := map[string]int{ "1": 22, "2": 11, "3": 0, "4": 55, "5": 66, } fmt.Println("修改之前key=", my_map["3"]) fmt.Println(my_map) fmt.Println("") test(my_map, "3") fmt.Println("修改之后key=", my_map["3"]) fmt.Println(my_map) } func test(m map[string]int, key string) { m[key] += 1 }
輸出結(jié)果如下
修改之前key= 0
map[1:22 2:11 3:0 4:55 5:66]
修改之后key= 1
map[1:22 2:11 3:1 4:55 5:66]
到此這篇關(guān)于Go語言學(xué)習(xí)之映射(map)的用法詳解的文章就介紹到這了,更多相關(guān)Go語言映射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解如何在golang項(xiàng)目開發(fā)中創(chuàng)建自己的Module
既然我們使用了很多開源的 module為我們的日常開發(fā)提供了很多的便捷性,那我們?cè)撊绾螌?shí)現(xiàn)自己的 module 來提供給團(tuán)隊(duì)中使用,接下小編就給大家介紹一下在golang項(xiàng)目開發(fā)如何創(chuàng)建自己的Module,需要的朋友可以參考下2023-09-09Golang使用Docker進(jìn)行集成測(cè)試的示例詳解
集成測(cè)試需要解決外部依賴問題,如?MySQL、Redis、網(wǎng)絡(luò)等依賴,本文就來聊聊?Go?程序如何使用?Docker?來解決集成測(cè)試中外部依賴問題吧2023-07-07Golang?Compare?And?Swap算法詳細(xì)介紹
CAS算法是一種有名的無鎖算法。無鎖編程,即不使用鎖的情況下實(shí)現(xiàn)多線程之間的變量同步,也就是在沒有線程被阻塞的情況下實(shí)現(xiàn)變量的同步,所以也叫非阻塞同步Non-blocking?Synchronization2022-10-10