1.類型定義
映射表 也叫,鍵值對(duì)集合, key=>value 對(duì)集合。
不同于數(shù)組和切片(索引值對(duì)集合)下表僅僅是由 0 開始逐一遞增的整型,map 的下標(biāo)(鍵)可以是任意的可比較類型(目前為止,只有切片是不可比較類型),最常用的還是整型和字符串型。
映射表還被稱為 關(guān)聯(lián)數(shù)組,哈希表。
定義語(yǔ)法:map[keyT]valueT
代碼示例:
func main() {
var userSet map[uint]string
fmt.Printf("%T\n", userSet) // map[uint]string
fmt.Println(userSet) // map[]
}
不限定元素的數(shù)量,操作上也沒(méi)有容量的概念。僅僅需要依據(jù) key 和 value 的類型,進(jìn) 行元素操作即可。
代碼演示:
func main() {
userSet := map[uint]string{}
userSet[12] = "張大錘"
userSet[22] = "李二錘"
fmt.Println(userSet) // map[12:張大錘 22:李二錘]
}
注意:
- 與 slice 一致,map 類型也是引用類型。
- 僅僅 var 聲明但未指定初始值的話,使用 nil 作為零值,不能直接繼續(xù)后續(xù)的操作,還是建議使用 make()或者是字面量的方式進(jìn)行聲明。
- 與切片和數(shù)組的差異:
切片和數(shù)組的下標(biāo),永遠(yuǎn)是從 0 開始逐一遞增的整數(shù),表示的元素的位置。
映射表,下標(biāo) key,不表示元素位置,僅僅是與值對(duì)應(yīng)關(guān)系。不能使用下標(biāo)去衡量元素 的位置和順序。(map 元素的是無(wú)序的)
2.鍵的數(shù)據(jù)類型是可以等值比較(==)的任意數(shù)據(jù)類型
演示,布爾型和數(shù)組型都可以:
m2 := map[bool]int{
false: 1,
true: 1000,
}
fmt.Println(m2)
m3 := map[[2]int]int {
[2]int{1, 2}: 42,
[2]int{3, 4}: 1024,
}
fmt.Println(m3)
3.字面量
字面量語(yǔ)法如下:
map[keyT]valueT{}
map[keyT]valueT{
key1: value1,
key2: value2,
}
示例:
userSet := map[uint]string{}
m2 := map[bool]int{
false: 1,
true: 1000,
}
4.引用類型
map 型數(shù)據(jù)結(jié)構(gòu),也包含數(shù)據(jù)值的地址,也是引用類型。
演示:
m6 := map[string]int{
"hank": 42,
"blockchain": 1024,
}
m7 := m6
m7["hank"] = 365
fmt.Println(m6, m7)
// 輸出:map[blockchain:1024 hank:365] map[blockchain:1024 hank:365]
5.map的元素是無(wú)序的
- 存儲(chǔ)的順序,與語(yǔ)法的順序不能保證一致。
- 遍歷獲取元素是順序,不能保證一致:一指的是不能保證與語(yǔ)法順序一致; 二指的是不能保證每次遍歷的順序一致。
遍歷的語(yǔ)法仍然是 for range
6.操作
1)[] key 操作
通過(guò)[] 利用 key,訪問(wèn)到特定的元素。
代碼:
m4 := map[string]int{
"hank": 42,
"fire": 1024,
"links": 365,
}
fmt.Println(m4["hank"]) // 42
key := "links"
fmt.Println(m4[key]) // 365
fmt.Println(m4["f"+"i"+"re"]) // 1024
2)len(),元素個(gè)數(shù)
m1 := map[string]int{
"hank": 42,
"fire": 1024,
"links": 365,
}
fmt.Println(len(m1)) // 3
3)存在判斷
當(dāng)使用[]key 的方案,訪問(wèn)元素時(shí),若指定的元素不存在,則會(huì)返回元素類型的零值。
代碼演示:
m4 := map[string]int{
"hank": 42,
"fire": 1024,
"links": 365,
}
fmt.Println(m4["chains"]) // 0
m5 := map[string]bool{
"yes": true,
}
fmt.Println(m5["no"]) // false
可見(jiàn),訪問(wèn)不存在的元素,不會(huì)導(dǎo)致失敗,反而會(huì)常規(guī)返回內(nèi)容。因此不能區(qū)別,是否存在 該元素。
若需要明確,該元素是否存在,則需要使用判定語(yǔ)法,如下:
value, exists := mapData[key]
在獲取值時(shí),利用多值返回的方案來(lái)獲取,返回的第二個(gè)值,是布爾值,用于表示是否獲取 成功(是否存在該元素),演示:
m4 := map[string]int{
"hank": 42,
"fire": 1024,
"links": 365
}
v1, exists := m4["hank"]
fmt.Println(v1, exists) // 42 true
v2, e := m4["chains"]
fmt.Println(v2, e) // 0 false
因此,在需要判斷的場(chǎng)合,先判斷 e 的值,再處理元素值,例如:
m4 := map[string]int{
"hank": 42,
"fire": 1024,
"links": 365
}
v3, e := m4["blockchain"]
if !e { // 不存在
v3 = 666 // 默認(rèn)值
}
fmt.Println(v3) // 666
4)delete(), 刪除元素
map 的元素可以被刪除。
使用內(nèi)置函數(shù) delete()實(shí)現(xiàn),語(yǔ)法: delete(map, key1, key2...)
代碼演示:
m4 := map[string]int{
"hank": 42,
"fire": 1024,
"links": 365,
}
fmt.Println(m4["fire"]) //1024
delete(m4, "fire")
fmt.Println(m4, m4["fire"]) // map[hank:42 links:365] 0
5)nil比較
nil 是 map 的零值,當(dāng)僅僅使用 var 聲明類型時(shí),map 為 nil。
代碼演示:
var m7 map[string]int
fmt.Println(m7, m7 == nil) // map[] true
6.for range 遍歷
語(yǔ)法上和數(shù)組及切片一致:
支持,同時(shí)獲取 key 和 value,僅僅獲 key,和僅獲取 value ,語(yǔ)法如下:
for k, v := range m7 {
fmt.Println(k, v)
}
for k := range m7 {
fmt.Println(k)
}
for _, v := range m7 {
fmt.Println(v)
}
示例:
m7 := map[string]int{
"hank": 42,
"blockchain": 1024,
"firelinks": 365,
}
for k, v := range m7 {
fmt.Println(k, v)
}
for k := range m7 {
fmt.Println(k)
}
for _, v := range m7 {
fmt.Println(v)
}
注意:
遍歷獲取元素是順序,不能保證一致:一指的是不能保證與語(yǔ)法順序一致,二指的是不能保證每次遍歷的順序一致。
7.Set性,集合性
在 GO 經(jīng)常將 map 類型,作為 set 集合類型看待。set 類型具備典型特征,map 都具
備:
- 元素不能重復(fù)
- 元素?zé)o序
體現(xiàn)在 map 上,通過(guò) key 進(jìn)行體現(xiàn)的。
在 map 中,key 是不能重復(fù)而且是無(wú)序的。
代碼:
set := map[string]int{
"hank": 42,
"firelinks": 365,
"hank": 1024,
}
fmt.Println(set) // 報(bào)錯(cuò): # command-line-arguments .\map.go:98:3: duplicate key "hank" in map literal
因此在程序處理時(shí),若需要使用 set 集合,map 的元素值,意義不大,通常為一個(gè)最簡(jiǎn) 單的數(shù)據(jù)結(jié)構(gòu)即可,代碼演示如下:
//典型的集合
set := map[string]int8{
"hank": 1,
"fire": 1,
"links": 1,
"blockchain": 1,
}
for k := range set {
fmt.Println(k)
}
_, e := set["hank"]
if e {
} else {
}
8.映射表元素不可用& 來(lái)取地址
映射表又稱 關(guān)聯(lián)數(shù)組(哈希表),建立鍵和值的關(guān)系,通常叫做哈希函數(shù),也叫映射函數(shù)。
在 map 中,維護(hù)的函數(shù),函數(shù)的參數(shù)就是 key,函數(shù)的返回值就是 value,即:
value(valueAddress) = mapFunc(key)
由于是算出來(lái)的,可見(jiàn)元素是動(dòng)態(tài)的,不能完全確定其位置。所以產(chǎn)生語(yǔ)法現(xiàn)象為: 映射表的元素,不能直接使用 & 來(lái)去地址。(但是 array,slice 就可以直接使用&對(duì)元素取地址)。
代碼演示:
//數(shù)組元素取地址, ok
arr := [...]int{1,2,3,4}
ep := &arr[2]
*ep = 33
fmt.Println(arr, ep)
//map 的元素取地址,失敗
m := map[string]int{
"hank":42,
"fire": 1024,
}
p := &m["hank"] // 報(bào)錯(cuò):cannot take the address of m["hank"]