最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

簡單聊聊Go?for?range中容易踩的坑

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

前言

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

線性結構:數(shù)組、隊列

非線性結構:樹、圖

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

遞歸(recursion):在函數(shù)內調用自身,將復雜情況逐步轉化成基本情況

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

(編程)迭代(iterate):按順序訪問線性結構中的每一項

遍歷(traversal):按規(guī)則訪問非線性結構中的每一項

下面會挑選幾個經(jīng)典的案例,一塊來探討下,看看如何避免掉坑,多積累積累采坑經(jīng)驗。

1. 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)
??}
}

不出意料,輸出結果為

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

這題比較簡單,就是簡單的傳值操作,大家應該都能答上來。下面加大難度,改為傳址操作

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

好好想想應該輸出什么結果呢?還是跟案例一是一樣的結果嗎?難道會有坑?

不出意料,還是出了意外,輸出結果為

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

為什么呢?

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

解決方案

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

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

輸出結果:

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

3.for+閉包

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

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

一眼看過去,感覺是輸出1 2 3,但實際會輸出 3 3 3

為什么呢?

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

輸出結果:

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

一眼看過去,感覺是會無序輸出1 2 3 4 5,但實際會輸出 5 5 5 5 5

為什么呢?

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

解決方案

和前面兩個案例解決方案一樣,是在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()

輸出結果:

5
4
2
1
3

注意是1~5無序輸出

總結

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

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

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

相關文章

  • Go Resiliency庫中timeout實現(xiàn)原理及源碼解析

    Go Resiliency庫中timeout實現(xiàn)原理及源碼解析

    Go-Resiliency庫中的timeout是一種基于協(xié)程的超時機制,通過創(chuàng)建協(xié)程來執(zhí)行任務并設置超時時間,若任務執(zhí)行時間超時則中止協(xié)程并返回錯誤,需要詳細了解可以參考下文
    2023-05-05
  • Golang底層原理解析String使用實例

    Golang底層原理解析String使用實例

    這篇文章主要為大家介紹了Golang底層原理解析String使用實例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • 一文帶你感受Go語言空結構體的魔力

    一文帶你感受Go語言空結構體的魔力

    在?Go?語言中,有一種特殊的用法可能讓許多人感到困惑,那就是空結構體,本文將對Go空結構體進行詳解,準備一杯你最喜歡的飲料或茶,隨著本文一探究竟吧
    2023-05-05
  • 使用go操作redis的有序集合(zset)

    使用go操作redis的有序集合(zset)

    這篇文章主要介紹了使用go操作redis的有序集合(zset),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go中空接口的具體使用

    go中空接口的具體使用

    空接口是一種特殊的接口類型,它不包含任何方法,本文主要介紹了go中空接口的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2025-04-04
  • Go語言開發(fā)環(huán)境搭建與初探(Windows平臺下)

    Go語言開發(fā)環(huán)境搭建與初探(Windows平臺下)

    Go是Google開發(fā)的一種編譯型,並發(fā)型,并具有垃圾回收功能的編程語言,可能很多人想學習go語言,那么首先就要了解go語言的環(huán)境配置方法
    2014-10-10
  • gtoken替換jwt實現(xiàn)sso登錄的問題小結

    gtoken替換jwt實現(xiàn)sso登錄的問題小結

    這篇文章主要介紹了gtoken替換jwt實現(xiàn)sso登錄,主要介紹了替換jwt的原因分析及gtoken的優(yōu)勢,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • golang中的jwt使用教程流程分析

    golang中的jwt使用教程流程分析

    這篇文章主要介紹了golang中的jwt使用教程,接下來我們需要講解一下Claims該結構體存儲了token字符串的超時時間等信息以及在解析時的Token校驗工作,需要的朋友可以參考下
    2023-05-05
  • 一文帶你了解Golang中interface的設計與實現(xiàn)

    一文帶你了解Golang中interface的設計與實現(xiàn)

    本文就來詳細說說為什么說?接口本質是一種自定義類型,以及這種自定義類型是如何構建起?go?的?interface?系統(tǒng)的,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-01-01
  • Go語言二進制文件的讀寫操作

    Go語言二進制文件的讀寫操作

    本文主要介紹了Go語言二進制文件的讀寫操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04

最新評論

景德镇市| 麻阳| 卢龙县| 建德市| 建昌县| 肇东市| 乌拉特中旗| 锦屏县| 潮州市| 瓦房店市| 勃利县| 忻州市| 资兴市| 上饶市| 兖州市| 龙南县| 阜新| 仁化县| 涿州市| 弥勒县| 开平市| 广饶县| 五大连池市| 和龙市| 大方县| 平湖市| 西贡区| 新乡县| 五家渠市| 景洪市| 汤阴县| 甘洛县| 克拉玛依市| 江西省| 武宣县| 永年县| 嫩江县| 巴东县| 丁青县| 乌兰县| 长丰县|