Go入門(mén)12:映射 map,引用類型

map 是一種特殊的數(shù)據(jù)結(jié)構(gòu):一種元素對(duì)(pair)的無(wú)序集合歉摧,pair 的一個(gè)元素是key,對(duì)應(yīng)的另一個(gè)元素是value,所以這個(gè)結(jié)構(gòu)也稱為關(guān)聯(lián)數(shù)組或字典叁温。

map的讀取和設(shè)置也類似slice一樣再悼,通過(guò)key來(lái)操作,只是slice的index只能是int類型膝但,而map多了很多類型冲九,可以是int,可以是string及所有完全定義了==與!=操作的類型跟束。

初始化

map 是引用類型莺奸,可以使用如下聲明:

make(map[KeyType]ValueType, initialCapacity)

make(map[KeyType]ValueType)

map[KeyType]ValueType{}

map[KeyType]ValueType{key1 : value1, key2 : value2, ... , keyN : valueN}

//聲明一個(gè)key是字符串,值為int的字典冀宴,這種方式的聲明需要在使用之前使用make初始化

var numbers map[string]int

numbers = make(map[string]int)

numbers["one"] = 1

numbers["two"] = 2

numbers["three"] = 3

未初始化的 map 的值是 nil灭贷。

func test1() {

? ? map1 := make(map[string]string, 5)? // 指定初始容量

? ? map2 := make(map[string]string)

? ? map3 := map[string]string{}

? ? map4 := map[string]string{"a": "1", "b": "2", "c": "3"}

? ? fmt.Println(map1, map2, map3, map4) // map[] map[] map[] map[a:1 b:2 c:3]

}

以上示例代碼用4種方式分別創(chuàng)建map,其中第一種和第二種的區(qū)別在于花鹅,有沒(méi)有指定初始容量,不過(guò)使用的時(shí)候則無(wú)需在意這些枫浙,因?yàn)閙ap的本質(zhì)決定了刨肃,一旦容量不夠,它會(huì)自動(dòng)擴(kuò)容箩帚。

注意:必須要先初始化才能給map賦值設(shè)置元素真友,不然會(huì)引起 panic: assign to entry in nil map。

func main(){

? ? ages01 := map[string]int{

? ? ? ? "alice":31,

? ? ? ? "bob":13,

? ? }

? ? ages02 := make(map[string]int)

? ? ages02["chris"] =20 ? ?// 通過(guò)==進(jìn)行map賦值

? ? ages02["paul"] = 30

? ? //age01和age02兩種初始化的方式等價(jià)

? ? m1 := make(map[string]int)

? ? m2 := map[string]int{}

? ? //m1和m2創(chuàng)建方式等價(jià)紧帕,都是創(chuàng)建了一個(gè)空的的map盔然,這個(gè)時(shí)候m1和m2沒(méi)有任何元素

? ? for name,age := range ages01{

? ? ? ? fmt.Printf("%s\t%d\n",name,age) ? ?// bob 13, alice 31

? ? }

? ? for name,age := range ages02{

? ? ? ? fmt.Printf("%s\t%d\n",name,age) ? ?// chris 20, paul 30

? ? }

? ? var null_map map[string]int? ? //聲明但未初始化map,此時(shí)是map的零值狀態(tài)(只有一個(gè)nil元素)

? ? empty_map := map[string]int{}? //創(chuàng)建了初始化了一個(gè)空的的map是嗜,這個(gè)時(shí)候empty_map沒(méi)有任何元素

? ? fmt.Println(m1 != nil && m2 != nil) //true

? ? fmt.Println(len(null_map)==0) ? ?// true

? ? fmt.Println(null_map ==nil)? ? //true,此時(shí)是map的零值狀態(tài)(nil)

? ? fmt.Println(len(empty_map)==0) ? ?// true

? ? fmt.Println(empty_map ==nil)? ? //false,空的的map不等價(jià)于nil(map的零值狀態(tài))

? ? empty_map["test"] = 12? ? ? ? ? //執(zhí)行正常愈案,空的的map可以賦值設(shè)置元素

? ? null_map["test"] = 12? ? ? ? ? ? //panic: assignment to entry in nil map,無(wú)法給未初始化的map賦值設(shè)置元素

}

需要注意的幾點(diǎn)

1)map是無(wú)序的鹅搪,每次打印出來(lái)的map都會(huì)不一樣站绪,它不能通過(guò)index獲取,而必須通過(guò)key獲壤鍪痢恢准;

2)map的長(zhǎng)度是不固定的,也就是和slice一樣甫题,也是一種引用類型馁筐;

3)內(nèi)置的len函數(shù)同樣適用于map,返回map擁有的key的數(shù)量坠非;

4)map的值可以很方便的修改敏沉,通過(guò)numbers["one"]=11可以很容易的把key為one的字典值該為11;

5)map和其他基本類型不同,它不是thread-safe赦抖,在多個(gè)go-routine存取時(shí)舱卡,必須使用mutex lock機(jī)制;

map元素的同步更改

m := make(map[string]string)

m["hello"] = "Hello"

m1 := m

m1["hello"] = "World"

map是一種引用類型队萤,如果兩個(gè)map同時(shí)指向一個(gè)底層轮锥,那么一個(gè)改變,另一個(gè)也相應(yīng)的改變要尔。

map中元素是否存在

rating := map[string]float32 {"c":5, "Go":4.5, "Python":5.2, "PHP":2.4}

csharpRating, ok := rating["c#"]

if ok {

? ? // 存在

} else {

? ? // 不存在

}

if _, ok := map[key]; ok {?

//如果存在則執(zhí)行?

}

map元素遍歷

range for 可用于遍歷map 中所有的元素舍杜,不過(guò)需要注意因?yàn)?map本身是無(wú)序的,因此對(duì)于程序的每次執(zhí)行赵辕,不能保證使用 range for 遍歷 map的順序總是一致的既绩。例如:

package main

import (?

? ? "fmt"

)

func main() {?

? ? personSalary := map[string]int{

? ? ? ? "steve": 12000,

? ? ? ? "jamie": 15000,

? ? }

? ? personSalary["mike"] = 9000

? ? for key, value := range personSalary {

? ? ? ? fmt.Printf("personSalary[%s] = %d\n", key, value)

? ? }

}

獲取map中所有的key

sizes := map[string]int{"XL": 20,"L":? 10,"M":? 5}

// Loop over map and append keys to empty slice.

keys := []string{}

for key, _ := range sizes {

? ? keys = append(keys, key)

}

// This is a slice of the keys.

fmt.Println(keys)

map元素增刪改查

首先這里map元素的增加和修改元素的語(yǔ)法一致,只需要map[K]=V即可还惠。例如:

package main

import (

? ? "fmt"

)

func main() {

? ? personSalary := make(map[string]int)

? ? personSalary["steve"] = 12000? ? //增加元素

? ? personSalary["jamie"] = 15000? ? //增加元素

? ? personSalary["mike"] = 9000? ? ? //增加元素

? ? fmt.Println("map before change", personSalary)

? ? personSalary["mike"] = 10000? ? //修改元素

? ? fmt.Println("map after change", personSalary)

}

輸出:

map before change map[steve:12000 jamie:15000 mike:9000]

map after change map[steve:12000 jamie:15000 mike:10000]

刪除元素需要使用內(nèi)置函數(shù) delete饲握,該函數(shù)根據(jù)鍵來(lái)刪除一個(gè)元素。需要強(qiáng)調(diào)delete函數(shù)沒(méi)有返回值蚕键,例如:

package main

import (?

? ? "fmt"

)

func main() {?

? ? personSalary := map[string]int{

? ? ? ? "steve": 12000,

? ? ? ? "jamie": 15000,

? ? }

? ? personSalary["mike"] = 9000

? ? fmt.Println("map before deletion", personSalary)

? ? delete(personSalary, "steve")

? ? fmt.Println("map after deletion", personSalary)

}

輸出:

map before deletion map[steve:12000 jamie:15000 mike:9000]?

map after deletion map[mike:9000 jamie:15000]

map作為函數(shù)參數(shù)

func main() {

? ? colors := map[string]int {

? ? ? ? "blue":? 10,

? ? ? ? "green": 20,

? ? }

? ? PrintGreen(colors)

}

func PrintGreen(colors map[string]int) {

? ? fmt.Println(colors["green"])

}

按key進(jìn)行排序

import (

? ? "fmt"

? ? "sort"

)

func main() {

? ? m := make(map[int]string)

? ? m[1] = "b"

? ? m[2] = "c"

? ? m[0] = "a"

? ? var keys []int

? ? for k := range m {

? ? ? ? keys = append(keys, k)

? ? }

? ? sort.Ints(keys) ? ?// 排序:升序

? ? for _, k := range keys {

? ? ? ? fmt.Println("Key:", k, "Value:", m[k])

? ? }

}

map的比較

Go 語(yǔ)言中map和slice救欧,func一樣,不支持 == 操作符锣光,就是不能直接比較笆怠。唯一合法的就是和nil作比較,判斷該map是不是零值狀態(tài)誊爹。

如果想自定義一個(gè)函數(shù)蹬刷,來(lái)比較兩個(gè)map是否相等,就可以遍歷比較它們的鍵和值是否完全相等频丘,代碼如下:

? ? func map_equal(x,y map[string]string) bool {

? ? ? if len(x) != len(y) {

? ? ? ? return false

? ? ? }

? ? ? for k,xv :=range x {

? ? ? ? if yv,ok := y[k]; !ok || yv != xv {

? ? ? ? ? ? ? ? ? return false

? ? ? ? ? ? ? ? }

? ? ? }

? ? ? return true

? ? }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末办成,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子搂漠,更是在濱河造成了極大的恐慌诈火,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件状答,死亡現(xiàn)場(chǎng)離奇詭異冷守,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)惊科,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)拍摇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人馆截,你說(shuō)我怎么就攤上這事充活》淅颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵混卵,是天一觀的道長(zhǎng)映穗。 經(jīng)常有香客問(wèn)我,道長(zhǎng)幕随,這世上最難降的妖魔是什么蚁滋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮赘淮,結(jié)果婚禮上辕录,老公的妹妹穿的比我還像新娘。我一直安慰自己梢卸,他們只是感情好走诞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蛤高,像睡著了一般蚣旱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戴陡,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天塞绿,我揣著相機(jī)與錄音,去河邊找鬼猜欺。 笑死位隶,一個(gè)胖子當(dāng)著我的面吹牛拷窜,可吹牛的內(nèi)容都是我干的开皿。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼篮昧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赋荆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起懊昨,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窄潭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后酵颁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體嫉你,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年躏惋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幽污。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡簿姨,死狀恐怖距误,靈堂內(nèi)的尸體忽然破棺而出簸搞,到底是詐尸還是另有隱情,我是刑警寧澤准潭,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布趁俊,位于F島的核電站,受9級(jí)特大地震影響刑然,放射性物質(zhì)發(fā)生泄漏寺擂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一闰集、第九天 我趴在偏房一處隱蔽的房頂上張望沽讹。 院中可真熱鬧,春花似錦武鲁、人聲如沸爽雄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挚瘟。三九已至,卻和暖如春饲梭,著一層夾襖步出監(jiān)牢的瞬間乘盖,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工憔涉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留订框,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓兜叨,卻偏偏與公主長(zhǎng)得像穿扳,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子国旷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容