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 ...
随机推荐
- 什么是CPC,CPA,CVR,CTR,ROI
合格的网络营销人员都应该熟悉下面的常见英文缩写,这些都是我们必须知道的名词解释:CVR (Click Value Rate): 转化率,衡量CPA广告效果的指标CTR (Click Through R ...
- tomcat下的日志配置详细说明
#可配置项(5类日志):catalina.localhost.manager.admin.host-manager handlers = 1catalina.org.apache.juli.FileH ...
- 第八讲 shiro 整合 ssm
1.整合ssm并且实现用户登录和菜单权限 2.将shiro整合到ssm中 (1)添加shiro相关jar包 (2)在web.xml中添加shiro配置 <!-- 新增shiro配置 --> ...
- C#索引器1 数字作为索引号
5.索引器 数字作为索引号 public class IndexerClass { private string[] name = new string[2]; public string thi ...
- 九、ARM 汇编与 C 的混合编程
9.1 ARM 汇编与 C 的混合编程 9.1.1 内嵌汇编 __asm __asm("指令")例如关闭/打开总中断开关 CPSR __asm //使用 C 中变量名代替寄存器 { ...
- zookeeper之四 Curator客户端的使用
Curator是一个开源的zookeeper客户端,解决了很多zookeeper原生客户端非常底层的细节开发工作,如连接重试.反复注册watcher等. public class CuratorOpe ...
- PHP程序员要看的书单
想提升自己,还得多看书!多看书!多看书! 下面是我收集到的一些PHP程序员应该看得书单及在线教程,自己也没有全部看完.共勉吧! Github地址:https://github.com/52fhy/ph ...
- 搭建DHCP服务实现动态分配IP地址-NTP网络时间同步
本节所讲内容: DHCP服务器工作原理 使用DHCP为局域网中的机器分配IP地址 使用DHCP为服务器分配固定IP地址 ntpdate加计划任务同步服务器时间 实验环境: 服务端:xuegod63 ...
- man wc
WC(1) User Commands/用户命令 WC(1) NAME/名称 wc - print the number of newlines, wo ...
- 使用IDEA连接mysql数据库
1.IDEA配置数据库连接 2.添加数据库: 3.填写数据库信息: database输入框里面填写要连接的数据库名称 然后点击test connection,会弹出一个框,提示下载驱动,点击进行下载即 ...