Go基礎(chǔ)-006-03 復(fù)合數(shù)據(jù)類型 映射表

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"]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容