go语言,循环语句引用外部变量导致错误

前言: 在工作实际开发中,遇到这个问题;记录一下。

1. 先看问题代码
func main() {
	wg:= errgroup.Group
	 pageIndex := 0
	
	for i := 0; i < 5; i++ {
		pageIndex++
		wg.Go(func() error {
			fmt.Println("pageIndex", pageIndex)
			return nil
		})
	}
	if err := wg.Wait(); err != nil {
		fmt.Println("err")
	}
	fmt.Println("ok")
}
//打印结果
pageIndex: 5
pageIndex: 5
pageIndex: 5
pageIndex: 5
pageIndex: 5
ok
原因:

通过打印发现,pageIndex全部是5,因为wg.Go里面的pageIndex是外部变量(该变量内存地址一直没有发生改变);go协程里面是先得到pageIndex内存地址,然后根据地址取值;当for循环执行完毕,pageIndex此时完成累加(值为5);go协程再去执行打印pageIndex的时候就全都是5了。(有可能某个groutine执行的够快。会打印出不同的值)
根据代码解释会更清楚一些

func main() {
	wg:= errgroup.Group
	 pageIndex := 0
	
	for i := 0; i < 5; i++ {
		pageIndex++
		wg.Go(func() error {
			//第一个groutine拿到pageIndex的地址:0xc666,虽然此时0x666的值为1;但是还没执行
			//第二个groutine拿到pageIndex的地址:0xc666,虽然此时0x666的值为2;但是还没执行
			//第三个groutine拿到pageIndex的地址:0xc666,虽然此时0x666的值为3;但是还没执行
			//......
			fmt.Println("pageIndex", pageIndex)
			return nil
		})
	}
	//最后拿到pageIndex的地址:0x666,此时0x666的值为5, groutine再执行打印语句,根据0x666得到结果为5
	if err := wg.Wait(); err != nil {
		fmt.Println("err")
	}
	fmt.Println("ok")
}
//打印结果
pageIndex: 5
pageIndex: 5
pageIndex: 5
pageIndex: 5
pageIndex: 5
ok
正确姿势
func main() {
	wg:= errgroup.Group
	//pageIndex := 0
	
	for i := 0; i < 5; i++ {
		//for循环内部创建变量
		pageIndex := i + 1
		wg.Go(func() error {
			//第一次拿到pageIndex的地址:0xc661,虽然此时0x661的值为1;但是还没执行
			//第二次拿到pageIndex的地址:0xc662,虽然此时0x662的值为2;但是还没执行
			//第三次拿到pageIndex的地址:0xc663,虽然此时0x663的值为3;但是还没执行
			//......
			fmt.Println("pageIndex", pageIndex)
			return nil
		})
	}
	//groutine执行打印语句,根据不同的内存地址获得不同的值
	if err := wg.Wait(); err != nil {
		fmt.Println("err")
	}
	fmt.Println("ok")
}
//打印结果
pageIndex: 5
pageIndex: 2
pageIndex: 3
pageIndex: 4
pageIndex: 1
ok

如果在内部新建变量的话,每个pageIndex的内存地址都不一样,因此可以根据不同的内存地址拿到不同的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值