Go語(yǔ)言map實(shí)現(xiàn)順序讀取
Go 語(yǔ)言中的 map 是一種非常強(qiáng)大的數(shù)據(jù)結(jié)構(gòu),它允許我們快速地存儲(chǔ)和檢索鍵值對(duì)。
然而,當(dāng)我們遍歷 map 時(shí),會(huì)有一個(gè)有趣的現(xiàn)象,那就是輸出的鍵值對(duì)順序是不確定的。
現(xiàn)象
先看一段代碼示例:
package main
import "fmt"
func main() {
? ? m := map[string]int{
? ? ? ? "apple": ?1,
? ? ? ? "banana": 2,
? ? ? ? "orange": 3,
? ? }
? ? for k, v := range m {
? ? ? ? fmt.Printf("key=%s, value=%d\n", k, v)
? ? }
}當(dāng)我們多執(zhí)行幾次這段代碼時(shí),就會(huì)發(fā)現(xiàn),輸出的順序是不同的。
原因
首先,Go 語(yǔ)言 map 的底層實(shí)現(xiàn)是哈希表,在進(jìn)行插入時(shí),會(huì)對(duì) key 進(jìn)行 hash 運(yùn)算。這也就導(dǎo)致了數(shù)據(jù)不是按順序存儲(chǔ)的,和遍歷的順序也就會(huì)不一致。
第二,map 在擴(kuò)容后,會(huì)發(fā)生 key 的搬遷,原來(lái)落在同一個(gè) bucket 中的 key,搬遷后,有些 key 可能就到其他 bucket 了。
而遍歷的過(guò)程,就是按順序遍歷 bucket,同時(shí)按順序遍歷 bucket 中的 key。
搬遷后,key 的位置發(fā)生了重大的變化,有些 key 被搬走了,有些 key 則原地不動(dòng)。這樣,遍歷 map 的結(jié)果就不可能按原來(lái)的順序了。
最后,也是最有意思的一點(diǎn)。
那如果說(shuō)我已經(jīng)初始化好了一個(gè) map,并且不對(duì)這個(gè) map 做任何操作,也就是不會(huì)發(fā)生擴(kuò)容,那遍歷順序是固定的嗎?
答:也不是。
Go 杜絕了這種做法,主要是擔(dān)心程序員會(huì)在開(kāi)發(fā)過(guò)程中依賴(lài)穩(wěn)定的遍歷順序,因?yàn)檫@是不對(duì)的。
所以在遍歷 map 時(shí),并不是固定地從 0 號(hào) bucket 開(kāi)始遍歷,每次都是從一個(gè)隨機(jī)值序號(hào)的 bucket 開(kāi)始遍歷,并且是從這個(gè) bucket 的一個(gè)隨機(jī)序號(hào)的 cell 開(kāi)始遍歷。
如何順序讀取
如果希望按照特定順序遍歷 map,可以先將鍵或值存儲(chǔ)到切片中,然后對(duì)切片進(jìn)行排序,最后再遍歷切片。
改造一下上面的代碼,讓它按順序輸出:
package main
import (
? ? "fmt"
? ? "sort"
)
func main() {
? ? m := map[string]int{
? ? ? ? "apple": ?1,
? ? ? ? "banana": 2,
? ? ? ? "orange": 3,
? ? }
? ? // 將 map 中的鍵存儲(chǔ)到切片中
? ? keys := make([]string, 0, len(m))
? ? for k := range m {
? ? ? ? keys = append(keys, k)
? ? }
? ? // 對(duì)切片進(jìn)行排序
? ? sort.Strings(keys)
? ? // 按照排序后的順序遍歷 map
? ? for _, k := range keys {
? ? ? ? fmt.Printf("key=%s, value=%d\n", k, m[k])
? ? }
}在上面的代碼中,首先將 map 中的鍵存儲(chǔ)到一個(gè)切片中,然后對(duì)切片進(jìn)行排序。
最后,按照排序后的順序遍歷 map。這樣就可以按照特定順序輸出鍵值對(duì)了。
參考文章:
https://golang.design/go-questions/map/unordered/
到此這篇關(guān)于Go語(yǔ)言map實(shí)現(xiàn)順序讀取的文章就介紹到這了,更多相關(guān)Go map順序讀取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Go語(yǔ)言不提供隱式數(shù)字轉(zhuǎn)換的原因
本文主要介紹了淺談Go語(yǔ)言不提供隱式數(shù)字轉(zhuǎn)換的原因,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
解析Golang和Java的優(yōu)勢(shì)與劣勢(shì)
Golang和Java是兩種流行的編程語(yǔ)言,它們?cè)诤芏喾矫嬗兄嗨浦?但也存在一些重要的區(qū)別,本文將對(duì)Golang和Java進(jìn)行對(duì)比,探討它們的特點(diǎn)和適用場(chǎng)景,需要的朋友可以參考下2023-10-10
golang控制結(jié)構(gòu)select機(jī)制及使用示例詳解
這篇文章主要介紹了golang控制結(jié)構(gòu)select機(jī)制及使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Go中make函數(shù)和append函數(shù)的作用詳解
本文給大家介紹Go中make函數(shù)和append函數(shù)的作用詳解,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-10-10

