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

簡(jiǎn)單聊聊Go?for?range中容易踩的坑

 更新時(shí)間:2023年03月20日 16:03:53   作者:勁仔Go&王中陽(yáng)Go  
for循環(huán)問(wèn)題,在面試中經(jīng)常都會(huì)被問(wèn)到,并且在實(shí)際業(yè)務(wù)項(xiàng)目中也經(jīng)常用到for循環(huán),要是沒(méi)用好,一不下心就掉坑,本文就來(lái)講講Go?for?range中容易踩的坑吧

前言

為了讓大家更好的理解本期知識(shí)點(diǎn),先介紹以下幾個(gè)知識(shí)點(diǎn):線性結(jié)構(gòu)、非線性結(jié)構(gòu)、循環(huán)、迭代、遍歷、遞歸。

線性結(jié)構(gòu):數(shù)組、隊(duì)列

非線性結(jié)構(gòu):樹(shù)、圖

循環(huán)(loop):最基礎(chǔ)的概念,所有重復(fù)的行為都是循環(huán)

遞歸(recursion):在函數(shù)內(nèi)調(diào)用自身,將復(fù)雜情況逐步轉(zhuǎn)化成基本情況

(數(shù)學(xué))迭代(iterate):在多次循環(huán)中逐步接近結(jié)果

(編程)迭代(iterate):按順序訪問(wèn)線性結(jié)構(gòu)中的每一項(xiàng)

遍歷(traversal):按規(guī)則訪問(wèn)非線性結(jié)構(gòu)中的每一項(xiàng)

下面會(huì)挑選幾個(gè)經(jīng)典的案例,一塊來(lái)探討下,看看如何避免掉坑,多積累積累采坑經(jīng)驗(yàn)。

1. for+傳值

先來(lái)到開(kāi)胃菜,熱熱身~

type?student?struct?{
??name?string
??age??int
}

func?main()?{
??m?:=?make(map[string]student)
??stus?:=?[]student{
????{name:?"張三",?age:?18},
????{name:?"李四",?age:?23},
????{name:?"王五",?age:?26},
??}
??for?_,?stu?:=?range?stus?{
????m[stu.name]?=?stu
??}
??for?k,?v?:=?range?m?{
????fmt.Println(k,?"=>",?v.name)
??}
}

不出意料,輸出結(jié)果為

李四 => 李四
王五 => 王五
張三 => 張三

這題比較簡(jiǎn)單,就是簡(jiǎn)單的傳值操作,大家應(yīng)該都能答上來(lái)。下面加大難度,改為傳址操作

2. for+傳址

將案例一改為傳址操作

type?student?struct?{
??name?string
??age??int
}

func?main()?{
??m?:=?make(map[string]*student)
??stus?:=?[]student{
????{name:?"張三",?age:?18},
????{name:?"李四",?age:?23},
????{name:?"王五",?age:?26},
??}
??for?_,?stu?:=?range?stus?{
????m[stu.name]?=?&stu
??}
??for?k,?v?:=?range?m?{
????fmt.Println(k,?"=>",?v.name)
??}
}

好好想想應(yīng)該輸出什么結(jié)果呢?還是跟案例一是一樣的結(jié)果嗎?難道會(huì)有坑?

不出意料,還是出了意外,輸出結(jié)果為

張三 => 王五
李四 => 王五
王五 => 王五

為什么呢?

  • 首先,關(guān)鍵點(diǎn)在于Go的for循環(huán),對(duì)循環(huán)變量stu每次是循環(huán)并不是迭代(簡(jiǎn)單的說(shuō),就是對(duì)循環(huán)變量stu只會(huì)做一次聲明和內(nèi)存地址的分配,后面循環(huán)就是不斷更新值);
  • 所以,取址操作 &stu,其實(shí)都是取的同一個(gè)變量的地址,只是值被循環(huán)更新為最后一個(gè)元素的值;
  • 最終,輸出的v.name,都是最后一個(gè)元素的name為王五

解決方案

在for循環(huán)中,做同名變量覆蓋stu:=stu(即重新聲明一個(gè)局部變量,做值拷貝,避免相互影響)

type?student?struct?{
??name?string
??age??int
}

func?main()?{
??m?:=?make(map[string]*student)
??stus?:=?[]student{
????{name:?"張三",?age:?18},
????{name:?"李四",?age:?23},
????{name:?"王五",?age:?26},
??}
??for?_,?stu?:=?range?stus?{
????stu?:=?stu??//同名變量覆蓋
????m[stu.name]?=?&stu
??}
??for?k,?v?:=?range?m?{
????fmt.Println(k,?"=>",?v.name)
??}
}

輸出結(jié)果:

張三 => 張三
李四 => 李四
王五 => 王五

3.for+閉包

在for循環(huán)里,做閉包操作,也是很容易掉坑的??纯聪旅孑敵鍪裁??

var?prints?[]func()
for?_,?v?:=?range?[]int{1,?2,?3}?{
??prints?=?append(prints,?func()?{?fmt.Println(v)?})
}
for?_,?print?:=?range?prints?{
??print()
}

一眼看過(guò)去,感覺(jué)是輸出1 2 3,但實(shí)際會(huì)輸出 3 3 3

為什么呢?

  • 首先,在分析了案例二后,我們知道了Go的for循環(huán)對(duì)循環(huán)變量v,其實(shí)每次是循環(huán)并不是迭代;
  • 然后,閉包=函數(shù)+引用環(huán)境,在同一個(gè)引用環(huán)境下,循環(huán)變量v的值會(huì)被不斷的覆蓋;
  • 所以最終,在打印時(shí),輸出的v,都是最后一個(gè)值3。

解決方案

和案例二解決方案一樣,是在for循環(huán)中,做同名變量覆蓋v:=v

var?prints?[]func()
for?_,?v?:=?range?[]int{1,?2,?3}?{
??v?:=?v?//同名變量覆蓋??
??prints?=?append(prints,?func()?{?fmt.Println(v)?})
}
for?_,?print?:=?range?prints?{
??print()
}

輸出結(jié)果:

1
2
3

4. for+goroutine

在for循環(huán)里,起goroutine協(xié)程,也是很迷惑很容易掉坑的??纯聪旅孑敵鍪裁??

var?wg?sync.WaitGroup
strs?:=?[]string{"1",?"2",?"3",?"4",?"5"}
for?_,?str?:=?range?strs?{
??wg.Add(1)
??go?func()?{
????defer?wg.Done()
????fmt.Println(str)
??}()
}
wg.Wait()

一眼看過(guò)去,感覺(jué)是會(huì)無(wú)序輸出1 2 3 4 5,但實(shí)際會(huì)輸出 5 5 5 5 5

為什么呢?

  • 首先,要記得Go的for循環(huán)對(duì)循環(huán)變量str,其實(shí)每次是循環(huán)并不是迭代;
  • 然后,main協(xié)程會(huì)和新起的協(xié)程做相互博弈,看誰(shuí)執(zhí)行更快,按這個(gè)案例執(zhí)行情況來(lái)看,main協(xié)程執(zhí)行速度明顯比新起的協(xié)程會(huì)更快,所以str被更新為最后一個(gè)元素值5(備注:并非絕對(duì));
  • 最終,在新起的協(xié)程中,使用str時(shí)值都為5,作為結(jié)果去輸出;
  • 拓展:如果在新起協(xié)程前,sleep個(gè)5s,輸出結(jié)果又會(huì)截然不同,感興趣的同學(xué)可以自行實(shí)驗(yàn)下,然后逐步深入地了解下GMP調(diào)度機(jī)制。

解決方案

和前面兩個(gè)案例解決方案一樣,是在for循環(huán)中,做同名變量覆蓋str:=str

var?wg?sync.WaitGroup
strs?:=?[]string{"1",?"2",?"3",?"4",?"5"}
for?_,?str?:=?range?strs?{
??str?:=?str?//同名變量覆蓋
??wg.Add(1)
??go?func()?{
????defer?wg.Done()
????fmt.Println(str)
??}()
}
wg.Wait()

輸出結(jié)果:

5
4
2
1
3

注意是1~5無(wú)序輸出

總結(jié)

for循環(huán)中做傳址、閉包、goroutine相關(guān)操作,千萬(wàn)要注意,一不小心就會(huì)很容易掉坑。

使用好同名變量覆蓋v:=v,這個(gè)解決大法,能很便捷的解決這一類問(wèn)題。

到此這篇關(guān)于簡(jiǎn)單聊聊Go for range中容易踩的坑的文章就介紹到這了,更多相關(guān)Go for range內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入淺出Go:掌握基礎(chǔ)知識(shí)的關(guān)鍵要點(diǎn)

    深入淺出Go:掌握基礎(chǔ)知識(shí)的關(guān)鍵要點(diǎn)

    Go是一種開(kāi)源的編程語(yǔ)言,由Google開(kāi)發(fā),它具有簡(jiǎn)潔、高效、并發(fā)性強(qiáng)的特點(diǎn),適用于構(gòu)建可靠的、高性能的軟件系統(tǒng),本文將介紹Go的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2023-10-10
  • Go語(yǔ)言中如何通過(guò)方法為類型添加行為

    Go語(yǔ)言中如何通過(guò)方法為類型添加行為

    這篇文章主要介紹了Go語(yǔ)言中如何通過(guò)方法為類型添加行為的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏的解決方案詳解

    Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏的解決方案詳解

    這篇文章主要為大家詳細(xì)介紹了當(dāng)Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏時(shí)蓋如何解決,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-07-07
  • golang中cache組件的使用及groupcache源碼解析

    golang中cache組件的使用及groupcache源碼解析

    本篇主要解析groupcache源碼中的關(guān)鍵部分, lru的定義以及如何做到同一個(gè)key只加載一次。緩存填充以及加載抑制的實(shí)現(xiàn)方法,本文重點(diǎn)給大家介紹golang中cache組件的使用及groupcache源碼解析,感興趣的朋友一起看看吧
    2021-06-06
  • Go返回int64類型字段超出javascript Number范圍的解決方法

    Go返回int64類型字段超出javascript Number范圍的解決方法

    這篇文章主要介紹了Go返回int64類型字段超出javascript Number范圍的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • GO?CountMinSketch計(jì)數(shù)器(布隆過(guò)濾器思想的近似計(jì)數(shù)器)

    GO?CountMinSketch計(jì)數(shù)器(布隆過(guò)濾器思想的近似計(jì)數(shù)器)

    這篇文章主要介紹了GO?CountMinSketch計(jì)數(shù)器(布隆過(guò)濾器思想的近似計(jì)數(shù)器),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-09-09
  • Golang unsafe包中的類型和函數(shù)詳解

    Golang unsafe包中的類型和函數(shù)詳解

    Golang中的unsafe包用于在運(yùn)行時(shí)進(jìn)行低級(jí)別的操作,這些操作通常是不安全的,因?yàn)榭梢源蚱艷olang的類型安全性和內(nèi)存安全性,使用 unsafe包的程序可能會(huì)影響可移植性和兼容性,接下來(lái)看下unsafe包中的類型和函數(shù)
    2023-08-08
  • Golang單元測(cè)試與覆蓋率的實(shí)例講解

    Golang單元測(cè)試與覆蓋率的實(shí)例講解

    這篇文章主要介紹了Golang單元測(cè)試與覆蓋率的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • Go基于GORM 獲取當(dāng)前請(qǐng)求所執(zhí)行的 SQL 信息(思路詳解)

    Go基于GORM 獲取當(dāng)前請(qǐng)求所執(zhí)行的 SQL 信息(思路詳解)

    這篇文章主要介紹了Go基于GORM 獲取當(dāng)前請(qǐng)求所執(zhí)行的 SQL 信息(思路詳解),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • gin?session中間件使用及源碼流程分析

    gin?session中間件使用及源碼流程分析

    這篇文章主要為大家介紹了gin?session中間件使用及源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10

最新評(píng)論