Go 語言 map 如何順序讀取?

Go 語言中的 map 是一種非常強大的數據結構,它允許我們快速地存儲和檢索鍵值對。

然而,當我們遍歷 map 時,會有一個有趣的現象,那就是輸出的鍵值對順序是不確定的。

現象

先看一段代碼示例:

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)
    }
}

當我們多執行幾次這段代碼時,就會發現,輸出的順序是不同的。

原因

首先,Go 語言 map 的底層實現是哈希表,在進行插入時,會對 key 進行 hash 運算。這也就導致了數據不是按順序存儲的,和遍歷的順序也就會不一致。

第二,map 在擴容後,會發生 key 的搬遷,原來落在同一個 bucket 中的 key,搬遷後,有些 key 可能就到其他 bucket 了。

而遍歷的過程,就是按順序遍歷 bucket,同時按順序遍歷 bucket 中的 key。

搬遷後,key 的位置發生了重大的變化,有些 key 被搬走了,有些 key 則原地不動。這樣,遍歷 map 的結果就不可能按原來的順序了。

最後,也是最有意思的一點。

那如果說我已經初始化好了一個 map,並且不對這個 map 做任何操作,也就是不會發生擴容,那遍歷順序是固定的嗎?

答:也不是。

Go 杜絕了這種做法,主要是擔心程序員會在開發過程中依賴穩定的遍歷順序,因爲這是不對的。

所以在遍歷 map 時,並不是固定地從 0 號 bucket 開始遍歷,每次都是從一個隨機值序號的 bucket 開始遍歷,並且是從這個 bucket 的一個隨機序號的 cell 開始遍歷。

如何順序讀取

如果希望按照特定順序遍歷 map,可以先將鍵或值存儲到切片中,然後對切片進行排序,最後再遍歷切片。

改造一下上面的代碼,讓它按順序輸出:

package main

import (
    "fmt"
    "sort"
)

func main() {
    m := map[string]int{
        "apple":  1,
        "banana": 2,
        "orange": 3,
    }

    // 將 map 中的鍵存儲到切片中
    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }

    // 對切片進行排序
    sort.Strings(keys)

    // 按照排序後的順序遍歷 map
    for _, k := range keys {
        fmt.Printf("key=%s, value=%d\n", k, m[k])
    }
}

在上面的代碼中,首先將 map 中的鍵存儲到一個切片中,然後對切片進行排序。

最後,按照排序後的順序遍歷 map。這樣就可以按照特定順序輸出鍵值對了。

以上就是本文的全部內容,如果覺得還不錯的話歡迎點贊轉發關注,感謝支持。


參考文章:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/iScSgfpSE2y14GH7JNRJSA