Go十大常见错误第10篇:Goroutine和循环变量一起使用的坑

2022年9月8日 357点热度 0人点赞 0条评论

前言

这是Go十大常见错误系列的第10篇:Goroutine和循环变量一起使用的坑。素材来源于Go布道者,现Docker公司资深工程师Teiva Harsanyi[1]

本文涉及的源代码全部开源在:Go十大常见错误源代码[2],欢迎大家关注公众号,及时获取本系列最新更新。

常见错误

对于Go初学者,很容易犯的一个错误就是goroutine和循环变量结合在一起使用时,错误地使用了循环变量。

比如下面这个例子:

ints := []int{123}
for _, i := range ints {
  go func() {
    fmt.Printf("%v\n", i)
  }()
}

这段程序的输出结果应该是什么?

Go初学者可能认为输出结果应该是1 2 3,但实际情况并不是。

这个例子里,3个goroutine共享同一个变量i,最后输出的结果大概率是输出3 3 3

要解决这个问题,主要有2个解决方案。

解决方案1

把循环变量i作为goroutine函数的一个参数,编译器在执行go func(i int)时,就会解析到i的值,确保每个goroutine可以拿到自己想要的值。

ints := []int{123}
for _, i := range ints {
  go func(i int) {
    fmt.Printf("%v\n", i)
  }(i)
}

解决方案2

创建一个新的变量,用于goroutine。

ints := []int{123}
for _, i := range ints {
  i := i
  go func() {
    fmt.Printf("%v\n", i)
  }()
}

推荐阅读

开源地址

文章和示例代码开源在GitHub: Go语言初级、中级和高级教程[3]

公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。

个人网站:Jincheng's Blog[4]

知乎:无忌[5]

福利

我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。

关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。还可以发送消息「进群」,和同行一起交流学习,答疑解惑。

References

  • https://itnext.io/the-top-10-most-common-mistakes-ive-seen-in-go-projects-4b79d4f6cd65

参考资料

[1]

Teiva Harsanyi: https://teivah.medium.com/

[2]

Go十大常见错误源代码: https://github.com/jincheng9/go-tutorial/tree/main/workspace/senior/p28

[3]

Go语言初级、中级和高级教程: https://github.com/jincheng9/go-tutorial

[4]

Jincheng's Blog: https://jincheng9.github.io/

[5]

无忌: https://www.zhihu.com/people/thucuhkwuji

84250Go十大常见错误第10篇:Goroutine和循环变量一起使用的坑

这个人很懒,什么都没留下

文章评论