中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站推廣每天必做的流程中視頻自媒體賬號注冊下載

網(wǎng)站推廣每天必做的流程,中視頻自媒體賬號注冊下載,wordpress create a network,廣州易網(wǎng)網(wǎng)站建設(shè)🔥 個人主頁:空白詩 🔥 熱門專欄:【Go語言精進之路】 文章目錄 引言一、什么是map1.1 map的基本概念與特性1.2 map的初始化與零值問題1.3 map作為引用類型的行為 二、map的基本操作2.1 插入數(shù)據(jù)2.2 獲取數(shù)據(jù)個數(shù)2.3 查找和數(shù)據(jù)讀取…

在這里插入圖片描述

🔥 個人主頁:空白詩
🔥 熱門專欄:【Go語言精進之路】

在這里插入圖片描述

文章目錄

    • 引言
    • 一、什么是`map`
      • 1.1 `map`的基本概念與特性
      • 1.2 map的初始化與零值問題
      • 1.3 `map`作為引用類型的行為
    • 二、`map`的基本操作
      • 2.1 插入數(shù)據(jù)
      • 2.2 獲取數(shù)據(jù)個數(shù)
      • 2.3 查找和數(shù)據(jù)讀取
      • 2.4 刪除數(shù)據(jù)
      • 2.5 遍歷數(shù)據(jù)
    • 三、map的內(nèi)部實現(xiàn)
      • 3.1 初始狀態(tài)
      • 3.2 `map`擴容
      • 3.3 `map`并發(fā)
    • 四、盡量使用cap參數(shù)創(chuàng)建map
    • 五、總結(jié)

在這里插入圖片描述

引言

在Go語言中,map 是一種無序的鍵值對集合,它以其高效的查找、插入和刪除操作而聞名。了解 map 的基本概念、特性和內(nèi)部實現(xiàn)機制,對于編寫高效且穩(wěn)定的Go代碼至關(guān)重要。本文將深入探討 map 的各個方面,包括其初始化、基本操作、內(nèi)部實現(xiàn)細節(jié),并討論為何在創(chuàng)建 map 時應(yīng)盡量使用帶有容量提示參數(shù)的做法。


一、什么是map

在這里插入圖片描述

1.1 map的基本概念與特性

map是Go語言中的一種內(nèi)建引用類型,它表示一組無序的鍵值對集合。每個鍵值對用冒號“:”分隔,其中鍵(key)是唯一的,用于標(biāo)識對應(yīng)的值(value)。map允許我們根據(jù)特定的鍵快速檢索、更新或刪除對應(yīng)的值。

在Go語言中,map對值(value)的數(shù)據(jù)類型沒有特定限制,它可以是任意類型,包括基本類型、結(jié)構(gòu)體、自定義類型等。但是,鍵(key)的類型有嚴(yán)格要求:key的類型必須可以通過“==”和“!=”操作符進行比較,這意味著鍵的類型需要是可比較的。因此,像函數(shù)、map和切片這樣不可比較的類型不能作為map的鍵。

1.2 map的初始化與零值問題

需要注意的是,map類型不支持“零值可用”,也就是說,未顯式初始化的map變量其默認(rèn)值為nil。嘗試對nilmap變量進行操作將會導(dǎo)致運行時錯誤(panic)。例如:

var m map[string]int  // 此時m的值為nil
// 下面的操作將會導(dǎo)致運行時panic,因為m未被初始化
m["key"] = 1 // panic: assignment to entry in nil map

為了避免這種情況,我們需要在使用map之前對其進行初始化??梢酝ㄟ^以下兩種方式之一來初始化map

  1. 使用make函數(shù)初始化:
m := make(map[string]int)
m["key"] = 1 // 現(xiàn)在這是安全的,因為m已經(jīng)被初始化
  1. 使用字面量初始化:
m := map[string]int{"key": 1}
// 或者
m := map[string]int{}
m["key"] = 1 // 同樣是安全的,因為m已經(jīng)被初始化

初始化后的map可以被安全地用于存儲和檢索鍵值對,而不會導(dǎo)致運行時錯誤。在Go程序中,map是非常有用的數(shù)據(jù)結(jié)構(gòu),特別適用于需要根據(jù)鍵快速查找、添加或刪除相應(yīng)值的場景。

1.3 map作為引用類型的行為

和切片一樣,map也是引用類型。這意味著,當(dāng)你將一個map類型的變量傳遞給函數(shù)時,實際上傳遞的是指向底層數(shù)據(jù)結(jié)構(gòu)的指針,而不是整個數(shù)據(jù)結(jié)構(gòu)的拷貝。因此,將map類型變量作為函數(shù)參數(shù)傳入不會有很大的性能消耗。

此外,由于在函數(shù)內(nèi)部和外部引用的是同一個底層數(shù)據(jù)結(jié)構(gòu),所以在函數(shù)內(nèi)部對map變量的修改(如添加、刪除鍵值對或更新值)在函數(shù)外部也是可見的。這種特性使得map在需要在多個函數(shù)或方法間共享和修改數(shù)據(jù)時非常有用。

以下是一個示例,展示了在函數(shù)內(nèi)部修改map,并在函數(shù)外部觀察到這些修改:

package mainimport "fmt"func modifyMap(m map[string]int) {// 在函數(shù)內(nèi)部修改mapm["apple"] = 5m["banana"] = 10
}func main() {// 初始化一個mapfruitMap := make(map[string]int)// 調(diào)用函數(shù),傳入map作為參數(shù)modifyMap(fruitMap)// 打印修改后的map,可以看到在modifyMap函數(shù)中所做的修改fmt.Println(fruitMap) // 輸出: map[apple:5 banana:10]
}

在這個例子中,modifyMap函數(shù)接收一個map作為參數(shù),并在函數(shù)內(nèi)部添加了兩個鍵值對。當(dāng)函數(shù)執(zhí)行完畢后,main函數(shù)中的fruitMap已經(jīng)被修改,反映了modifyMap函數(shù)中所做的更改。這是因為map是引用類型,modifyMap接收的是fruitMap的引用,因此對它的任何修改都會反映在原始map上。


二、map的基本操作

在這里插入圖片描述

2.1 插入數(shù)據(jù)

當(dāng)面對一個非nilmap類型變量時,我們可以向其中插入符合map類型定義的任意鍵值對。值得注意的是,如果試圖插入的鍵(key)已經(jīng)存在于map中,那么新的值將會覆蓋舊的值。Go運行時會管理map內(nèi)部的內(nèi)存,因此,除非系統(tǒng)內(nèi)存耗盡,否則我們不必?fù)?dān)心向map中插入大量數(shù)據(jù)。

m := make(map[string]int)
m["apple"] = 5  // 插入鍵值對 "apple": 5
m["apple"] = 7  // 更新鍵 "apple" 的值為 7,舊值5被覆蓋
m["banana"] = 10 // 插入鍵值對 "banana": 10

在上述代碼中,我們首先創(chuàng)建了一個從string類型到int類型的map。然后,我們插入了鍵值對"apple": 5。緊接著,我們嘗試再次插入鍵"apple",但這次賦予它一個新的值7。由于這個鍵已經(jīng)存在于map中,因此舊的值5會被新的值7覆蓋。最后,我們插入了一個新的鍵值對"banana": 10。

這種覆蓋行為是map的一個重要特性,它允許我們根據(jù)需要更新存儲在map中的值。在實際編程中,這一特性非常有用,比如當(dāng)我們需要根據(jù)某些條件動態(tài)改變值時。

2.2 獲取數(shù)據(jù)個數(shù)

要獲取map中數(shù)據(jù)的個數(shù),可以使用內(nèi)置的len()函數(shù)。

count := len(m)
fmt.Println("Number of items in map:", count) // 輸出map中的元素個數(shù)

len(m)返回m中當(dāng)前存儲的鍵值對數(shù)量。

2.3 查找和數(shù)據(jù)讀取

可以根據(jù)鍵來查找和讀取map中的數(shù)據(jù)。如果鍵不存在,則返回該類型的零值。

value, exists := m["apple"] // 查找鍵為"apple"的值,并檢查鍵是否存在
if exists {fmt.Println("The value of 'apple' is:", value)
} else {fmt.Println("'apple' does not exist in the map.")
}

使用value, exists := m[key]的格式可以同時獲取鍵對應(yīng)的值和該鍵是否存在。如果鍵存在,existstrue,并且value為該鍵對應(yīng)的值;如果鍵不存在,existsfalsevalue為該類型的零值。

2.4 刪除數(shù)據(jù)

要從map中刪除一個鍵值對,可以使用delete()函數(shù)。

delete(m, "banana") // 刪除鍵為"banana"的鍵值對

delete(m, key)函數(shù)會從m中刪除與key關(guān)聯(lián)的鍵值對。如果key不存在,則delete什么也不做。

2.5 遍歷數(shù)據(jù)

可以使用range關(guān)鍵字來遍歷map中的所有鍵值對。

package mainimport "fmt"func main() {m := map[int]int{1: 11, 2: 12, 3: 13,}fmt.Printf("{ ")for key, value := range m {fmt.Printf("key: %d, value: %d  ", key, value)}fmt.Printf(" }\n")
}

range m會迭代m中的所有鍵值對,每次迭代都會返回當(dāng)前的鍵和值。在上面的循環(huán)中,keyvalue分別被賦值為當(dāng)前迭代的鍵和值,然后打印出來。
在這里插入圖片描述

上面的輸出結(jié)果非常理想,給我們的表象是迭代器按照map中的元素插入次序逐一遍歷。那讓我們再多遍歷幾次這個map

package mainimport "fmt"func doIteration(m map[int]int) {fmt.Printf("{ ")for key, value := range m {fmt.Printf("key: %d, value: %d  ", key, value)}fmt.Printf(" }\n")
}func main() {m := map[int]int{1: 11,2: 12,3: 13,}for i := 0; i < 3; i++ {doIteration(m)}
}

在這里插入圖片描述

我們看見對同一map進行多次遍歷,遍歷的元素次序并不相同。這是因為Go運行時在初始化map迭代器時對起始位置做了隨機處理。因此千萬不要依賴遍歷map所得到的元素次序


三、map的內(nèi)部實現(xiàn)

在這里插入圖片描述
和切片相比,map類型的內(nèi)部實現(xiàn)要復(fù)雜得多。Go運行時使用一張哈希表來實現(xiàn)抽象的map類型,運行時實現(xiàn)了map操作的所有功能,包括查找、插入、刪除、遍歷等。本文這里只做一些簡單的介紹。

3.1 初始狀態(tài)

在Go語言中,當(dāng)一個map被初始化時,它會分配一個較小的內(nèi)存空間來存儲鍵值對數(shù)據(jù)。這個初始的內(nèi)存空間包含一定數(shù)量的桶(buckets),每個桶能夠存儲一個或多個鍵值對。初始狀態(tài)下,這些桶都是空的。

map的初始化可以通過字面量、make函數(shù)或者直接使用map類型進行。例如:

// 使用字面量初始化
m1 := map[string]int{"apple": 5, "banana": 10}// 使用make函數(shù)初始化
m2 := make(map[string]int)// 直接聲明map類型變量(需要后續(xù)進行初始化)
var m3 map[string]int
m3 = make(map[string]int)

在初始化時,map會預(yù)留一定的空間以準(zhǔn)備存儲鍵值對,但這個初始空間相對較小。

3.2 map擴容

當(dāng)map中的元素數(shù)量增加,負(fù)載因子(已存儲的鍵值對數(shù)量與桶的數(shù)量的比例)也會隨之增加。當(dāng)負(fù)載因子超過某個預(yù)定的閾值時,map會進行擴容以保證性能。

擴容過程中,map會創(chuàng)建一個更大的桶數(shù)組,并且重新計算所有現(xiàn)有鍵值對的哈希值,將它們重新分布到新的桶數(shù)組中。這個重新哈希和分布的過程是為了確保鍵值對能夠更均勻地分散在新的桶中,從而減少哈希沖突并提高查找效率。

擴容是一個相對昂貴的操作,因為它涉及到內(nèi)存分配和大量數(shù)據(jù)的遷移。因此,在實際使用中,如果可能的話,最好提前預(yù)估map的大小并一次性分配足夠的空間。

3.3 map并發(fā)

Go語言的map類型并不是并發(fā)安全的。這意味著如果多個goroutine同時對一個map進行讀寫操作,就可能導(dǎo)致數(shù)據(jù)競爭(data race)和不可預(yù)知的行為。

為了在并發(fā)環(huán)境中安全地使用map,有幾種常見的解決方案:

  1. 使用互斥鎖(Mutex):通過使用sync.Mutexsync.RWMutex來同步對map的訪問。在每次讀寫map之前,先獲取鎖,操作完成后再釋放鎖。

  2. 使用sync.Map:Go語言標(biāo)準(zhǔn)庫提供了一個并發(fā)安全的map實現(xiàn),即sync.Map。它內(nèi)部使用了分段鎖和其他優(yōu)化技術(shù)來提供高效的并發(fā)訪問。

  3. 通道(Channel):另一種方法是使用Go的通道來序列化對map的訪問。通過將所有對map的操作都通過一個或多個通道來進行,可以確保在同一時間只有一個goroutine能夠訪問map。

在實際應(yīng)用中,選擇哪種并發(fā)控制方法取決于具體的使用場景和性能要求。對于簡單的用例,使用互斥鎖可能就足夠了;而在需要高并發(fā)性能的場景中,sync.Map可能更為合適。


四、盡量使用cap參數(shù)創(chuàng)建map

在這里插入圖片描述
由于擴容是一個相對昂貴的操作,因為它涉及到內(nèi)存分配和大量數(shù)據(jù)的遷移,因此,如果可以的話我們最好對map使用規(guī)模做出粗略的估算,并使用cap參數(shù)對map實例進行初始化。

當(dāng)你創(chuàng)建一個 map 而不指定容量時,Go 會自動為你分配一個初始的、未指定的容量。這個容量足以滿足初始需求,并且隨著 map 中元素的增加,Go 的運行時會自動管理其內(nèi)部結(jié)構(gòu)的大小調(diào)整,以容納更多的元素。這是最常見也是最簡單的初始化方式。

m := make(map[string]int)

如果你在創(chuàng)建 map 時明確指定了 cap 參數(shù),你是在給 Go 提供一個關(guān)于你期望 map 最終可能包含多少個鍵值對的提示。這有助于減少 map 在增長過程中需要重新分配內(nèi)存的次數(shù),從而提高效率,尤其是在你知道 map 大致會有多大時。但請注意,指定的 cap 是一個提示而不是嚴(yán)格的限制,map 的實際容量可能會略高于指定的值,且 map 仍然可以在達到這個預(yù)設(shè)容量后繼續(xù)增長。

m := make(map[string]int, 100)

優(yōu)缺點分析:

  • 不使用 cap:簡化初始化過程,讓Go自動管理容量,適用于大多數(shù)情況,特別是當(dāng)你不確定map最終大小時。
  • 使用 cap:通過預(yù)先估計map的大小,可以略微優(yōu)化性能,減少動態(tài)擴容的次數(shù),適合于明確知道或能估算map容量的場景。

選擇是否使用 cap 主要取決于你對map最終規(guī)模的了解程度和對性能的特定需求。在不需要精確控制初始容量的情況下,省略 cap 是一個簡潔且有效的方法。然而,如果你正處理大量數(shù)據(jù)且關(guān)心性能優(yōu)化,明智地設(shè)定初始容量可以帶來益處。

下面對兩種初始化方式的性能進行對比:

package mainimport "testing"const mapSize = 10000func BenchmarkMapInitWithoutCap(b *testing.B) {for i := 0; i < b.N; i++ {m := make(map[int]int)for i := 0; i < mapSize; i++ {m[i] = i}}
}
func BenchmarkMapInitWithCap(b *testing.B) {for i := 0; i < b.N; i++ {m := make(map[int]int, mapSize)for i := 0; i < mapSize; i++ {m[i] = i}}
}

BenchmarkMapInitWithoutCap函數(shù)執(zhí)行以下操作:

  1. 它使用一個循環(huán),該循環(huán)將運行b.N次,其中b.Ntesting.B提供的,表示基準(zhǔn)測試應(yīng)該運行的次數(shù)。這是為了確保我們獲得足夠的數(shù)據(jù)點來平均性能測試結(jié)果,從而獲得更準(zhǔn)確的數(shù)據(jù)。

  2. 在每次循環(huán)中,它創(chuàng)建一個新的map,沒有指定初始容量(make(map[int]int))。

  3. 然后,它向這個map中插入mapSize(即10000)個鍵值對,其中鍵和值都是循環(huán)變量i。

這個基準(zhǔn)測試的目的是測量在不指定初始容量的情況下,初始化并填充一個map的性能。

執(zhí)行結(jié)果如下:
在這里插入圖片描述

BenchmarkMapInitWithCap函數(shù)與BenchmarkMapInitWithoutCap非常相似,但有一個關(guān)鍵區(qū)別:

  1. 在創(chuàng)建map時,它使用make(map[int]int, mapSize)來指定一個初始容量提示,這個容量提示等于將要插入的鍵值對的數(shù)量(即10000)。

這個基準(zhǔn)測試的目的是測量在指定了與將要插入的鍵值對數(shù)量相等的初始容量提示的情況下,初始化并填充一個map的性能。

下面是執(zhí)行結(jié)果:
在這里插入圖片描述
可以看出,使用cap參數(shù)的map實例的平均寫性能是不使用cap參數(shù)的2倍。


五、總結(jié)

本文通過詳細闡述了Go語言中 map 的基本概念、特性及其作為引用類型的行為,介紹了 map 的基本操作如插入、獲取數(shù)據(jù)個數(shù)、查找、刪除和遍歷數(shù)據(jù)等。同時,深入剖析了 map 的內(nèi)部實現(xiàn),包括其初始狀態(tài)、擴容機制以及并發(fā)問題。最后,本文強調(diào)了在使用 map 時,為了提高性能和減少內(nèi)存重新分配的次數(shù),應(yīng)盡量在創(chuàng)建時提供合理的容量提示參數(shù)。通過全面理解 map 的工作原理和最佳實踐,開發(fā)者可以更加有效地利用這一強大的數(shù)據(jù)結(jié)構(gòu)來優(yōu)化程序性能。

http://www.risenshineclean.com/news/29101.html

相關(guān)文章:

  • 后海做網(wǎng)站公司網(wǎng)站推廣的渠道有
  • 在國外怎么做網(wǎng)站服務(wù)營銷
  • 做時時彩網(wǎng)站被抓廣州新塘網(wǎng)站seo優(yōu)化
  • 文創(chuàng)產(chǎn)品設(shè)計方案范本優(yōu)化關(guān)鍵詞排名推廣
  • 江蘇省政府門戶網(wǎng)站建設(shè)html+css網(wǎng)頁制作成品
  • 酒業(yè)公司網(wǎng)站模板鄭州百度推廣公司
  • wordpress點贊代碼北京seo網(wǎng)絡(luò)優(yōu)化師
  • 鹽城市住房城鄉(xiāng)建設(shè)委官方網(wǎng)站海陽seo排名優(yōu)化培訓(xùn)
  • 手機網(wǎng)站建設(shè)設(shè)計手機百度app免費下載
  • 長沙建個網(wǎng)站一般需要多少錢網(wǎng)絡(luò)營銷策劃方案
  • 金華電子商務(wù)網(wǎng)站建設(shè)百度怎么做廣告推廣
  • 高端型網(wǎng)站制作永久免費google搜索引擎
  • 網(wǎng)站建設(shè) 安慶關(guān)鍵詞全網(wǎng)搜索工具
  • 利為匯wordpress教程廈門關(guān)鍵詞seo排名網(wǎng)站
  • 寧城網(wǎng)站建設(shè)公司百度怎么免費推廣
  • 游戲網(wǎng)站開發(fā)視頻制作一個簡單的網(wǎng)站
  • 公司網(wǎng)站沒備案最近營銷熱點
  • 東莞php網(wǎng)站建設(shè)快速排名seo
  • wordpress 整站帶數(shù)據(jù)互動營銷的方式有哪些
  • asp做微網(wǎng)站設(shè)計濟南網(wǎng)站seo公司
  • 自己做的網(wǎng)站標(biāo)題青島網(wǎng)絡(luò)推廣公司排名
  • 企業(yè)負(fù)責(zé)人電話名錄百度搜索優(yōu)化怎么做
  • 企業(yè)做網(wǎng)站有什么好處壞處百度愛采購優(yōu)化軟件
  • 傳媒公司做網(wǎng)站條件如何讓關(guān)鍵詞排名靠前
  • wordpress數(shù)據(jù)表開頭小紅書seo排名規(guī)則
  • wordpress換域名換服務(wù)器寧波seo在線優(yōu)化
  • 長沙網(wǎng)站搭建百度引流推廣費用多少
  • 網(wǎng)站內(nèi)容建設(shè)ppt目前最新的營銷方式有哪些
  • 東昌府網(wǎng)站建設(shè)公司營銷對企業(yè)的重要性
  • 網(wǎng)站開發(fā)必用代碼西安百度競價托管代運營