Go學(xué)習(xí)筆記-字典

字典在數(shù)學(xué)上的詞匯是映射,將一個(gè)集合中的所有元素關(guān)聯(lián)到另一個(gè)集合中的部分或全部元素,并且只能是一一映射或者多對(duì)一映射腕让。
image.png

數(shù)組切片讓我們具備了可以操作一塊連續(xù)內(nèi)存的能力,它是對(duì)同質(zhì)元素的統(tǒng)一管理歧斟。而字典則賦予了不連續(xù)不同類的內(nèi)存變量的關(guān)聯(lián)性纯丸,它表達(dá)的是一種因果關(guān)系,字典的 key 是因静袖,字典的 value 是果觉鼻。如果說(shuō)數(shù)組和切片賦予了我們步行的能力,那么字典則讓我們具備了跳躍的能力队橙。

指針坠陈、數(shù)組切片和字典都是容器型變量,字典比數(shù)組切片在使用上要簡(jiǎn)單很多喘帚,但是內(nèi)部結(jié)構(gòu)卻無(wú)比復(fù)雜畅姊。本節(jié)我們只專注字典的基礎(chǔ)使用,在后續(xù)的高級(jí)章節(jié)再來(lái)分析它的內(nèi)部結(jié)構(gòu)吹由。

字典的創(chuàng)建

關(guān)于 Go 語(yǔ)言有很多批評(píng)的聲音若未,比如說(shuō)它不支持范型。其實(shí)嚴(yán)格來(lái)說(shuō) Go 是支持范型的倾鲫,只不過(guò)很弱粗合,范型在 Go 語(yǔ)言里是一種很弱的存在。比如數(shù)組切片和字典類型都是支持范型的乌昔。在創(chuàng)建字典時(shí)隙疚,必須要給 key 和 value 指定類型。創(chuàng)建字典也可以使用 make 函數(shù)

package main

import "fmt"

func main() {
    var m map[int]string = make(map[int]string)
    fmt.Println(m, len(m))
}

----------
map[] 0

使用 make 函數(shù)創(chuàng)建的字典是空的磕道,長(zhǎng)度為零供屉,內(nèi)部沒(méi)有任何元素。如果需要給字典提供初始化的元素溺蕉,就需要使用另一種創(chuàng)建字典的方式伶丐。

package main

import "fmt"

func main() {
    var m map[int]string = map[int]string{
        90: "優(yōu)秀",
        80: "良好",
        60: "及格",  // 注意這里逗號(hào)不可缺少,否則會(huì)報(bào)語(yǔ)法錯(cuò)誤
    }
    fmt.Println(m, len(m))
}

---------------
map[90:優(yōu)秀 80:良好 60:及格] 3

字典變量同樣支持類型推導(dǎo)疯特,上面的變量定義可以簡(jiǎn)寫成

var m = map[int]string{
 90: "優(yōu)秀",
 80: "良好",
 60: "及格",
}

如果你可以預(yù)知字典內(nèi)部鍵值對(duì)的數(shù)量哗魂,那么還可以給 make 函數(shù)傳遞一個(gè)整數(shù)值,通知運(yùn)行時(shí)提前分配好相應(yīng)的內(nèi)存漓雅。這樣可以避免字典在長(zhǎng)大的過(guò)程中要經(jīng)歷的多次擴(kuò)容操作录别。

var m = make(map[int]string, 16)

字典的讀寫

同 Python 語(yǔ)言一樣朽色,字典可以使用中括號(hào)來(lái)讀寫內(nèi)部元素,使用 delete 函數(shù)來(lái)刪除元素组题。

package main

import "fmt"

func main() {
    var fruits = map[string]int {
        "apple": 2,
        "banana": 5,
        "orange": 8,
    }
    // 讀取元素
 var score = fruits["banana"]
    fmt.Println(score)

 // 增加或修改元素
    fruits["pear"] = 3
    fmt.Println(fruits)

 // 刪除元素
    delete(fruits, "pear")
    fmt.Println(fruits)
}

-----------------------
5
map[apple:2 banana:5 orange:8 pear:3]
map[orange:8 apple:2 banana:5]

字典 key 不存在會(huì)怎樣葫男?

刪除操作時(shí),如果對(duì)應(yīng)的 key 不存在往踢,delete 函數(shù)會(huì)靜默處理腾誉。遺憾的是 delete 函數(shù)沒(méi)有返回值,你無(wú)法直接得到 delete 操作是否真的刪除了某個(gè)元素峻呕。你需要通過(guò)長(zhǎng)度信息或者提前嘗試讀取 key 對(duì)應(yīng)的 value 來(lái)得知利职。

讀操作時(shí),如果 key 不存在瘦癌,也不會(huì)拋出異常猪贪。它會(huì)返回 value 類型對(duì)應(yīng)的零值。如果是字符串讯私,對(duì)應(yīng)的零值是空串热押,如果是整數(shù),對(duì)應(yīng)的零值是 0斤寇,如果是布爾型桶癣,對(duì)應(yīng)的零值是 false。

你不能通過(guò)返回的結(jié)果是否是零值來(lái)判斷對(duì)應(yīng)的 key 是否存在娘锁,因?yàn)?key 對(duì)應(yīng)的 value 值可能恰好就是零值牙寞,比如下面的字典你就不能判斷 "durin" 是否存在

var m = map[string]int {
  "durin": 0  // 舉個(gè)栗子而已,其實(shí)我還是喜歡吃榴蓮的
}

這時(shí)候必須使用字典的特殊語(yǔ)法莫秆,如下

package main

import "fmt"

func main() {
    var fruits = map[string]int {
        "apple": 2,
        "banana": 5,
        "orange": 8,
    }

    var score, ok = fruits["durin"]
    if ok {
        fmt.Println(score)
    } else {
        fmt.Println("durin not exists")
    }

    fruits["durin"] = 0
    score, ok = fruits["durin"]
    if ok {
        fmt.Println(score)
    } else {
        fmt.Println("durin still not exists")
    }
}

-------------
durin not exists
0

字典的下標(biāo)讀取可以返回兩個(gè)值间雀,使用第二個(gè)返回值都表示對(duì)應(yīng)的 key 是否存在河胎。初學(xué)者看到這種奇怪的用法是需要花時(shí)間來(lái)消化的辕羽,讀者不需要想太多,它只是 Go 語(yǔ)言提供的語(yǔ)法糖气筋,內(nèi)部并沒(méi)有太多的玄妙缝驳。正常的函數(shù)調(diào)用可以返回多個(gè)值连锯,但是并不具備這種“隨機(jī)應(yīng)變”的特殊能力 —— 「多態(tài)返回值」。

字典的遍歷

字典的遍歷提供了下面兩種方式用狱,一種是需要攜帶 value萎庭,另一種是只需要 key,需要使用到 Go 語(yǔ)言的 range 關(guān)鍵字齿拂。

package main

import "fmt"

func main() {
    var fruits = map[string]int {
        "apple": 2,
        "banana": 5,
        "orange": 8,
    }

    for name, score := range fruits {
        fmt.Println(name, score)
    }

    for name := range fruits {
        fmt.Println(name)
    }
}

------------
orange 8
apple 2
banana 5
apple
banana
orange

奇怪的是,Go 語(yǔ)言的字典沒(méi)有提供諸于 keys() 和 values() 這樣的方法肴敛,意味著如果你要獲取 key 列表署海,就得自己循環(huán)一下吗购,如下

package main

import "fmt"

func main() {
    var fruits = map[string]int {
        "apple": 2,
        "banana": 5,
        "orange": 8,
    }

    var names = make([]string, 0, len(fruits))
    var scores = make([]int, 0, len(fruits))

    for name, score := range fruits {
        names = append(names, name)
        scores = append(scores, score)
    }

    fmt.Println(names, scores)
}

----------
[apple banana orange] [2 5 8]

這會(huì)讓代碼寫起來(lái)比較繁瑣,不過(guò) Go 語(yǔ)言官方就是沒(méi)有提供砸狞,讀者還是努力習(xí)慣一下吧

線程(協(xié)程)安全

Go 語(yǔ)言的內(nèi)置字典不是線程安全的捻勉,如果需要線程安全,必須使用鎖來(lái)控制刀森。在后續(xù)鎖的章節(jié)里踱启,我們將會(huì)自己實(shí)現(xiàn)一個(gè)線程安全的字典。

字典變量里存的是什么研底?

字典變量里存的只是一個(gè)地址指針埠偿,這個(gè)指針指向字典的頭部對(duì)象。所以字典變量占用的空間是一個(gè)字榜晦,也就是一個(gè)指針的大小冠蒋,64 位機(jī)器是 8 字節(jié),32 位機(jī)器是 4 字節(jié)乾胶。

image.png

可以使用 unsafe 包提供的 Sizeof 函數(shù)來(lái)計(jì)算一個(gè)變量的大小

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var m = map[string]int{
        "apple":  2,
        "pear":   3,
        "banana": 5,
    }
    fmt.Println(unsafe.Sizeof(m))
}

------
8
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抖剿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子识窿,更是在濱河造成了極大的恐慌斩郎,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喻频,死亡現(xiàn)場(chǎng)離奇詭異缩宜,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)半抱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門脓恕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人窿侈,你說(shuō)我怎么就攤上這事炼幔。” “怎么了史简?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵乃秀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我圆兵,道長(zhǎng)跺讯,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任殉农,我火速辦了婚禮刀脏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘超凳。我一直安慰自己愈污,他們只是感情好耀态,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著暂雹,像睡著了一般首装。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杭跪,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天仙逻,我揣著相機(jī)與錄音,去河邊找鬼涧尿。 笑死系奉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的现斋。 我是一名探鬼主播喜最,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼庄蹋!你這毒婦竟也來(lái)了瞬内?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤限书,失蹤者是張志新(化名)和其女友劉穎虫蝶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體倦西,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡能真,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扰柠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粉铐。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卤档,靈堂內(nèi)的尸體忽然破棺而出蝙泼,到底是詐尸還是另有隱情,我是刑警寧澤劝枣,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布汤踏,位于F島的核電站,受9級(jí)特大地震影響舔腾,放射性物質(zhì)發(fā)生泄漏溪胶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一稳诚、第九天 我趴在偏房一處隱蔽的房頂上張望哗脖。 院中可真熱鬧,春花似錦、人聲如沸懒熙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)工扎。三九已至,卻和暖如春衔蹲,著一層夾襖步出監(jiān)牢的瞬間肢娘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工舆驶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橱健,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓沙廉,卻偏偏與公主長(zhǎng)得像拘荡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撬陵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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