<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
為了讓大家更好的理解本期知識點,先介紹以下幾個知識點:線性結構、非線性結構、迴圈、迭代、遍歷、遞迴。
線性結構:陣列、佇列
非線性結構:樹、圖
迴圈(loop):最基礎的概念,所有重複的行為都是迴圈
遞迴(recursion):在函數內呼叫自身,將複雜情況逐步轉化成基本情況
(數學)迭代(iterate):在多次迴圈中逐步接近結果
(程式設計)迭代(iterate):按順序存取線性結構中的每一項
遍歷(traversal):按規則存取非線性結構中的每一項
下面會挑選幾個經典的案例,一塊來探討下,看看如何避免掉坑,多積累積累採坑經驗。
先來到開胃菜,熱熱身~
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) } }
不出意料,輸出結果為:
李四 => 李四
王五 => 王五
張三 => 張三
這題比較簡單,就是簡單的傳值操作,大家應該都能答上來。下面加大難度,改為傳址操作
將案例一改為傳址操作
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) } }
好好想想應該輸出什麼結果呢?還是跟案例一是一樣的結果嗎?難道會有坑?
不出意料,還是出了意外,輸出結果為:
張三 => 王五
李四 => 王五
王五 => 王五
為什麼呢?
迴圈變數stu
每次是迴圈並不是迭代(簡單的說,就是對迴圈變數stu
只會做一次宣告和記憶體地址的分配,後面迴圈就是不斷更新值);&stu
,其實都是取的同一個變數的地址,只是值被迴圈更新為最後一個元素的值;v.name
,都是最後一個元素的name為王五
。解決方案:
在for迴圈中,做同名變數覆蓋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) } }
輸出結果:
張三 => 張三
李四 => 李四
王五 => 王五
在for迴圈裡,做閉包操作,也是很容易掉坑的。看看下面輸出什麼?
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
為什麼呢?
迴圈變數v
,其實每次是迴圈並不是迭代;閉包=函數+參照環境
,在同一個參照環境下,迴圈變數v的值會被不斷的覆蓋;解決方案:
和案例二解決方案一樣,是在for迴圈中,做同名變數覆蓋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
在for迴圈裡,起goroutine協程,也是很迷惑很容易掉坑的。看看下面輸出什麼?
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
為什麼呢?
迴圈變數str
,其實每次是迴圈並不是迭代;解決方案:
和前面兩個案例解決方案一樣,是在for迴圈中,做同名變數覆蓋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迴圈中做傳址、閉包、goroutine相關操作,千萬要注意,一不小心就會很容易掉坑。
使用好同名變數覆蓋v:=v
,這個解決大法,能很便捷的解決這一類問題。
到此這篇關於簡單聊聊Go for range中容易踩的坑的文章就介紹到這了,更多相關Go for range內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45