欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于golang中map使用的幾點(diǎn)注意事項(xiàng)總結(jié)(強(qiáng)烈推薦!)

 更新時(shí)間:2023年01月28日 11:31:33   作者:阿兵云原生  
map是一種無(wú)序的基于key-value的數(shù)據(jù)結(jié)構(gòu),Go語(yǔ)言中的map是引用類型,必須初始化才能使用,下面這篇文章主要給大家介紹了關(guān)于golang中map使用的幾點(diǎn)注意事項(xiàng),需要的朋友可以參考下

前言

日常的開(kāi)發(fā)工作中,map 這個(gè)數(shù)據(jù)結(jié)構(gòu)相信大家并不陌生,在 golang 里面,當(dāng)然也有 map 這種類型

關(guān)于 map 的使用,還是有蠻多注意事項(xiàng)的,如果不清楚,這些事項(xiàng),關(guān)鍵時(shí)候可能會(huì)踩坑,我們一起來(lái)演練一下吧

1 使用 map 記得初始化

寫一個(gè) demo

  • 定義一個(gè) map[int]int 類型的變量 myMap , 不做初始化
  • 我們可以讀取 myMap 的值,默認(rèn)為 零值
  • 但是我們往沒(méi)有初始化的 myMap 中寫入值,程序就會(huì) panic ,這里切記不要踩坑
func main(){

	var myMap map[int]int
	fmt.Println("myMap[1] ==  ",myMap[1])
}

程序運(yùn)行效果:

# go run main.go
myMap[1] ==   0

代碼中加入寫操作:

func main(){

	var myMap map[int]int
	fmt.Println("myMap[1] ==  ",myMap[1])

	myMap[1] = 10

	fmt.Println("myMap[1] ==  ",myMap[1])
}

程序運(yùn)行效果:

# go run main.go
myMap[1] ==   0
panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
        /home/admin/golang_study/later_learning/map_test/main.go:20 +0xf3
exit status 2

程序果然報(bào) panic 了,我們實(shí)際工作中需要萬(wàn)分小心,對(duì)代碼要有敬畏之心

2 map 的遍歷是無(wú)序的

定義一個(gè) map[int]int 類型的 map,并初始化 5 個(gè)數(shù)

func main() {
	myMap := map[int]int{
		1: 1,
		2: 2,
		3: 3,
		4: 4,
		5: 5}

	for k := range myMap {
		fmt.Println(myMap[k])
	}
}

程序運(yùn)行效果:

# go run main.go
1
2
3
4
5
# go run main.go
5
1
2
3
4
# go run main.go
3
4
5
1
2

運(yùn)行上述代碼 3 次,3 次結(jié)果都不一樣,當(dāng)然,也有可能 3 次結(jié)果的順序都是一樣的

因?yàn)?GO 中的 map 是基于哈希表實(shí)現(xiàn)的,所以遍歷的時(shí)候是無(wú)序的

若我們需要清空這個(gè) map ,那么我們可以直接將對(duì)應(yīng)的 map 變量置為 nil 即可,例如

myMap = nil

3 map 也可以是二維的

map 也是可以像數(shù)組一樣是二維的,甚至是多維的都可以,主要是看我們的需求了

可是我們要注意,只是定義的時(shí)候類似二維數(shù)組,但是具體使用的時(shí)候還是有區(qū)別的

我們可以這樣來(lái)操作二維數(shù)組

func main() {
	myMap := map[int]map[string]string{}
	myMap[0] = map[string]string{
		"name":"xiaomotong",
		"hobby":"program",
	}
	fmt.Println(myMap)
}

程序運(yùn)行效果:

# go run main.go
map[0:map[name:xiaomotong hobby:program]]

我們不可以這樣來(lái)操作二維數(shù)組

func main() {
	myMap := map[int]map[string]string{}
	myMap[0]["name"] = "xiaomotong"
	myMap[0]["hobby"] = "program"

	fmt.Println(myMap)
}

程序運(yùn)行效果:

# go run main.go
panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
        /home/admin/golang_study/later_learning/map_test/main.go:17 +0x7f
exit status 2

原因很簡(jiǎn)單,程序報(bào)的 panic 日志已經(jīng)說(shuō)明了原因

是因?yàn)?myMap[0] 鍵 是 0 沒(méi)問(wèn)題,但是 值是 map[string]string 類型的,需要初始化才可以做寫操作,這也是我們文章第一點(diǎn)所說(shuō)到的

要是還是想按照上面這種寫法來(lái),那也很簡(jiǎn)單,加一句初始化就好了

func main() {
	myMap := map[int]map[string]string{}
	myMap[0] = map[string]string{}
    
	myMap[0]["name"] = "xiaomotong"
	myMap[0]["hobby"] = "program"

	fmt.Println(myMap)
}

4 獲取 map 的 key 最好使用這種方式

工作中,我們會(huì)存在需要獲取一個(gè) map 的所有 key 的方式,這個(gè)時(shí)候,我們一般是如何獲取的呢,接觸過(guò)反射的 xdm 肯定會(huì)說(shuō),這很簡(jiǎn)單呀,用反射一句話就搞定的事情,例如:

func main() {
	myMap := map[int]int{
		1: 1,
		2: 2,
		3: 3,
		4: 4,
		5: 5}

	myKey := reflect.ValueOf(myMap).MapKeys()

	for v :=range myKey{
		fmt.Println(v)
	}
}

運(yùn)行程序go run main.go,結(jié)果如下:

可是我們都知道,golang 中的 反射 reflect 確實(shí)寫起來(lái)很簡(jiǎn)潔,但是效率真的非常低,我們平時(shí)使用最好還是使用下面這種方式

func main() {
	myMap := map[int]int{
		1: 1,
		2: 2,
		3: 3,
		4: 4,
		5: 5}

	myKey := make([]int,0,len(myMap))

	for k :=range myMap{
		myKey = append(myKey,myMap[k])
	}
	fmt.Println(myKey)
}

這種編碼方式,提前已經(jīng)設(shè)置好 myKey 切片的容量和 map 的長(zhǎng)度一致,則后續(xù)向 myKey 追加 key 的時(shí)候,就不會(huì)出現(xiàn)需要切片擴(kuò)容的情況

程序運(yùn)行效果:

# go run main.go
[2 3 4 5 1]

我們可以看到,拿出來(lái)的 key ,也不是有序的

5 map 是并發(fā)不安全的 ,sync.Map 才是安全的

最后咱們?cè)賮?lái)模擬一下和驗(yàn)證一下 golang 的 map 不是安全

模擬 map 不安全的 demo, 需要多開(kāi)一些協(xié)程才能模擬到效果,實(shí)驗(yàn)了一下,我這邊模擬開(kāi) 5 萬(wàn) 個(gè)協(xié)程

type T struct {
	myMap map[int]int
}

func (t *T) getValue(key int) int {
	return t.myMap[key]
}

func (t *T) setValue(key int, value int) {
	t.myMap[key] = value
}

func main() {

	ty := T{myMap: map[int]int{}}

	wg := sync.WaitGroup{}
	wg.Add(50000)
	for i := 0; i < 50000; i++ {

		go func(i int) {
			ty.setValue(i, i)
			fmt.Printf("get key == %d, value == %d \n", i, ty.getValue(i))
			wg.Done()
		}(i)
	}

	wg.Wait()
	fmt.Println("program over !!")
}

運(yùn)行程序變會(huì)報(bào)錯(cuò)如下信息:

# go run main.go
fatal error: concurrent map writes
...

如果硬是要使用 map 的話, 也可以加上一把互斥鎖就可以解決了

咱們只用修改上述的代碼,結(jié)構(gòu)體定義的位置,和 設(shè)置值的函數(shù)

type T struct {
	myMap map[int]int
	lock sync.RWMutex
}

func (t *T) setValue(key int, value int) {
	t.lock.Lock()
	defer t.lock.Unlock()
	t.myMap[key] = value
}

為了檢查方便,我們把程序輸出的值打印到一個(gè)文件里面 go run main.go >> map.log

程序運(yùn)行后,可以看到,真實(shí)打印的 key 對(duì)應(yīng)數(shù)據(jù),確實(shí)是有 5000 行,沒(méi)毛病

image-20211016221550721

通過(guò)以上例子,就可以明白 golang 中的 map,確實(shí)不是并發(fā)安全的,需要加鎖,才能做到并發(fā)安全
golang 也給我們提供了并發(fā)安全的 map ,sync.Map

sync.Map 的實(shí)現(xiàn)機(jī)制,簡(jiǎn)單來(lái)說(shuō),是他自身自帶鎖,因此可以控制并發(fā)安全

好了,今天就到這里,語(yǔ)言是好語(yǔ)言,工具也是好工具,我們需要實(shí)際用起來(lái)才能發(fā)揮他們的價(jià)值,不用的話一切都是白瞎

總結(jié)

到此這篇關(guān)于關(guān)于golang中map使用的幾點(diǎn)注意事項(xiàng)的文章就介紹到這了,更多相關(guān)golang map使用注意事項(xiàng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go實(shí)現(xiàn)冒泡排序算法

    go實(shí)現(xiàn)冒泡排序算法

    冒泡排序算法是數(shù)據(jù)結(jié)構(gòu)中常用的一種算法,本文就介紹了go實(shí)現(xiàn)冒泡排序算法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Go語(yǔ)言實(shí)現(xiàn)的最簡(jiǎn)單數(shù)獨(dú)解法

    Go語(yǔ)言實(shí)現(xiàn)的最簡(jiǎn)單數(shù)獨(dú)解法

    前面給大家介紹過(guò)使用javascript實(shí)現(xiàn)的簡(jiǎn)單的數(shù)獨(dú)解法,小伙伴們都非常喜歡,今天我們?cè)賮?lái)分享一則go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單的數(shù)獨(dú)解法,有需要的小伙伴來(lái)參考下。
    2015-03-03
  • GO語(yǔ)言中的方法值和方法表達(dá)式的使用方法詳解

    GO語(yǔ)言中的方法值和方法表達(dá)式的使用方法詳解

    這篇文章主要介紹了GO的方法值和方法表達(dá)式的使用方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Golang使用反射的動(dòng)態(tài)方法調(diào)用詳解

    Golang使用反射的動(dòng)態(tài)方法調(diào)用詳解

    Go是一種靜態(tài)類型的語(yǔ)言,提供了大量的安全性和性能。這篇文章主要和大家介紹一下Golang使用反射的動(dòng)態(tài)方法調(diào)用,感興趣的小伙伴可以了解一下
    2023-03-03
  • Go 請(qǐng)求兔子識(shí)別接口實(shí)現(xiàn)流程示例詳解

    Go 請(qǐng)求兔子識(shí)別接口實(shí)現(xiàn)流程示例詳解

    這篇文章主要為大家介紹了Go 請(qǐng)求兔子識(shí)別接口實(shí)現(xiàn)流程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • ubuntu安裝golang并設(shè)置goproxy的方法步驟

    ubuntu安裝golang并設(shè)置goproxy的方法步驟

    在Ubuntu系統(tǒng)上安裝Go語(yǔ)言(Golang)有多種方法,包括使用包管理器、從源代碼編譯安裝以及使用版本管理工具如gvm,安裝完成后,為了方便管理Go語(yǔ)言項(xiàng)目依賴,需要設(shè)置GOPATH環(huán)境變量并配置Go代理,本文介紹ubuntu安裝golang并設(shè)置goproxy的方法,感興趣的朋友一起看看吧
    2024-10-10
  • 通過(guò)手機(jī)案例理解Go設(shè)計(jì)模式之裝飾器模式的功能屬性

    通過(guò)手機(jī)案例理解Go設(shè)計(jì)模式之裝飾器模式的功能屬性

    這篇文章主要為大家介紹了Go設(shè)計(jì)模式之裝飾器模式的功能屬性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Golang實(shí)現(xiàn)支持多種類型的set

    Golang實(shí)現(xiàn)支持多種類型的set

    在項(xiàng)目開(kāi)發(fā)中,常常會(huì)用到set去重,為什么不寫一個(gè)set呢,而且go現(xiàn)在支持了泛型,所以本文就來(lái)用Golang實(shí)現(xiàn)一個(gè)支持多種類型的set呢
    2023-05-05
  • Golang切片和數(shù)組拷貝詳解(淺拷貝和深拷貝)

    Golang切片和數(shù)組拷貝詳解(淺拷貝和深拷貝)

    這篇文章主要為大家詳細(xì)介紹一下Golang切片拷貝和數(shù)組拷貝,文中有詳細(xì)的代碼示例供大家參考,需要的可以參考一下
    2023-04-04
  • Golang中深拷貝與淺拷貝詳解

    Golang中深拷貝與淺拷貝詳解

    這篇文章主要為大家詳細(xì)介紹一下Golang深拷貝和淺拷貝,文中有詳細(xì)的代碼示例供大家參考,需要的可以參考一下
    2023-05-05

最新評(píng)論