Golang闭包的坑
team leader 发现一个Golang程序的bug,是由不正确使用闭包引起。记载一下,以作备忘。
猜猜一下程序的结果:
package main
import (
"fmt"
"time"
) func main() {
arr := []int{, , , , , }
for _, num := range arr {
go func() {
fmt.Println(num) }()
} time.Sleep( * time.Second) }
~
闭包导致的结果如下:
dill@ubuntu-vm:~/GoProjcet/src/exercise$ go run closure.go
避免闭包:
package main import (
"fmt"
"time"
) func main() {
arr := []int{, , , , , }
for _, num := range arr {
go func(n int) {
fmt.Println(n) }(num)
} time.Sleep( * time.Second) }
得到想要的结果:
dill@ubuntu-vm:~/GoProjcet/src/exercise$ go run closure.go
说到原因,还要从匿名函数说起。
什么是匿名函数?
命名函数只能在包水平声明,但是我们可以在任意表达式中使用函数字面量的形式给一个函数赋值(相当于在函数中声明函数,不过该函数没有名字,作用域只在表达式内)。函数字面量很像函数声明的,但是在func关键字后没有跟谁函数名字。它是一个表达式,他的值被称为匿名函数。函数字面量使我们可以在用到的地方定义一个函数(随用随定义)。重点是,这种方式定义的函数,可以进入整个lexical 环境,以至于内部函数可以引用外围函数的变量。
本例中,变量单一num被所有的匿名函数共享,即go生成的所有协程均可访问到num,不幸的是num被随后的循环迭代更新。等新goroutinues开始执行时,循环已经更新num,开始下一轮迭代,甚至已经轮询完成。所以当这些goroutine读取num的值时,惊奇的发现,num已经变成了slice中的最后一个值。通过添加一个明确的参数,我们保证我们使用的值是当前go程序正在执行的值。
Golang闭包的坑的更多相关文章
- golang闭包里的坑
介绍 go的闭包是一个很有用的东西.但是如果你不了解闭包是如何工作的,那么他也会给你带来一堆的bug.这里我会拿出Go In Action这本书的一部分代码,来说一说在使用闭包的时候可能遇到的坑.全部 ...
- 【GoLang】golang 闭包 closure 参数传递的蹊跷!
结论: 闭包函数可以直接引用外层代码定义的变量, 但是,注意,闭包函数里面引用的是变量的地址, 当goroutine被调度时,改地址的值才会被传递给goroutine 函数. 介绍 go的闭包是一个很 ...
- Golang中的坑二
Golang中的坑二 for ...range 最近两周用Golang做项目,编写web服务,两周时间写了大概五千行代码(业务代码加单元测试用例代码).用Go的感觉很爽,编码效率高,运行效率也不错,用 ...
- Golang 中的坑 一
Golang 中的坑 短变量声明 Short variable declarations 考虑如下代码: package main import ( "errors" " ...
- Golang的防坑小技巧
Golang的防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名小白,在之前没有接触到编程的小伙伴,难免会踩到一些坑,比如说刚刚入门的时候你需要安装环境,学习Gol ...
- golang 闭包
说起golang闭包,在官方手册里面看过一次,没怎么用过,还是因为6哥经常用,阅读他的代码好多闭包,emmm,今天就学习一下. 在过去近十年时间里,面向对象编程大行其道,以至于在大学的教育里,老师也只 ...
- 初学者学习golang可能遇到的坑
我也是个golang初学者,刚入门的话,有些"坑"还是不好发现的.如map只是定义了然后就拿来使用,变量的值覆盖等. 本来打算写一篇的,后面发现有人写的挺不错的,我就把里面的有些坑 ...
- golang的哪些坑爷事: package实践
在golang中package是个困惑的概念, 特别是package还可以与folder不同名, 委实让我恶心了一把. 关于golang的package的最佳实践: package is folder ...
- Golang闭包案例分析与普通函数对比
闭包案例 package main import ( "fmt" "strings" //记住一定引入strings包 ) //①编写一个函数makeSuffi ...
随机推荐
- Java基础学习(2)
Java基础学习(二) 面向对象 对象:客观存在的事物 面向对象:人具体关注的事物的某些信息 类:是模子,确定对象会拥有的特征(属性)和行为(方法) 对象的属性:对象具有的各种特征 对象的方法:对象能 ...
- dll和ocx的区别
ActiveX,OLE是基于COM的一种应用,其文件后缀一般以dll和ocx结尾:ocx作为一种特殊的dll文件,具有一定的用户界面和事件响应,而dll文件只是方法和属性的集合. 一.关于DLL的介绍 ...
- Schedule HDU - 6180 (multiset , 贪心)
There are N schedules, the i-th schedule has start time si and end time ei (1 <= i <= N). Ther ...
- 神经网络训练技巧:训练参数初始化、Drop out及Batch Normalization
参数初始化: xavier初始化: https://blog.csdn.net/VictoriaW/article/details/73000632 条件:优秀的初始化应该使得各层的激活值和梯度的方差 ...
- 我用过的gitlab api
1.新增tag https://docs.gitlab.com/ee/api/tags.html#list-project-repository-tags 2.获取指定项目合分支的最新一次merge ...
- Vue this.$nextTick原理
虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做.比如一个新闻滚动的列表项.如果在这里需要操作dom, 应该是等待 Vue 完成更新 DO ...
- Flater-Provide狀態管理
參考來源:http://www.jspang.com/posts/2019/03/01/flutter-shop.html#%E7%AC%AC24%E8%8A%82%EF%BC%9Aprovide%E ...
- RPC vs REST
RPC vs REST 另外,由于Dubbo是基础框架,其实现的内容对于我们实施微服务架构是否合理,也需要我们根据自身需求去考虑是否要修改,比如Dubbo的服务调用是通过RPC实现的,但是如果仔细拜读 ...
- 原生JS 将时间转换成几秒前,几分钟前…常用于评论回复功能
//格式化时间 留备用~ function getDateDiff(dateStr) { var publishTime = dateStr / 1000, d_seconds, d_minutes, ...
- :last-child----represents the last element among a group of sibling elements.
CSS伪类 :last-child 代表在一群兄弟元素中的最后一个元素. 举个例子: 从代码和图可以看出:last-child选择了最后一个li标签. 同时,我们换另外一段代码,看看是否还有这样的效果 ...