Golang for range的坑

本篇参考自:https://blog.csdn.net/somanlee/article/details/107881231,尊重原创


废话就不说了,先来一段代码:
package main

import (
	"fmt"
)

func main() {

	slice := []int{0, 1, 2, 3}
	mp := make(map[int]*int)
	for index, value := range slice {
		mp[index] = &value
	}
	fmt.Println("-------------------------------------------------------------------")
	for key, value := range mp {
		fmt.Println(key, " ", *value)
	}
}

先猜一下输出的结果是什么,再看看结果跟你想的是不是一样的
在这里插入图片描述
没错,全都是 333333,就差个2了

其根本原因就是 for range是用一个变量承接rang 后面的内容,也就是上面的mp,slice,什么意思???
我们先看看为什么全都是3,稍微做出一点改变:

func main() {

	slice := []int{0, 1, 2, 3}
	mp := make(map[int]*int)
	for index, value := range slice {
		mp[index] = &value
		fmt.Println("address is:",&value)
		fmt.Println("value is:",value)
	}
	//根本原因在于for range是用一个变量承接mp中的内容的
	fmt.Println("-------------------------------------------------------------------")
	for key, value := range mp {
		fmt.Println(key, " ", *value)
	}
}

结果如下:
在这里插入图片描述
有没有发现,为什么地址都是一样的,而最后这个地址的值是3,mp中存的是又是这个地址,所以不全都是3了嘛。那又为什么会是这样了呢?上文中的承接是什么意思呢??

for range

for index, value := range t_slice {
	original body
}

相当于:

len_temp := len(t_slice)
range_temp := t_slice
for index_temp = 0; index_temp < len_temp; index_temp++ {
     value_temp := range_temp[index_temp]
     index := index_temp
     value := value_temp
     original body
}

这个承接的变量就是 range_temp。

正确的写法:

package main

import (
	"fmt"
)

func main() {

	slice := []int{0, 1, 2, 3}
	mp := make(map[int]*int)
	for index, value := range slice {
		num := value
		mp[index] = &num
		// mp[index] = &slice[index] 用切片的index也行
	}
	//根本原因在于for range是用一个变量承接mp中的内容的
	fmt.Println("-------------------------------------------------------------------")
	for key, value := range mp {
		fmt.Println(key, " ", *value)
	}
}

在for range中启动携程:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var m = []int{1, 2, 3}
	var wg sync.WaitGroup
	for i := range m {
		wg.Add(1)
 		go func() {
			fmt.Print(i)
			wg.Done()
    	}()
	}
	wg.Wait()
}

输出结果为:222
上面的代码中,每轮循环中使用匿名函数起协程,匿名函数直接引用外部变量i,实际上,这就是golang中的闭包,闭包是匿名函数与匿名函数所引用环境的组合,匿名函数有动态创建的特性,这使得匿名函数不用通过参数传递的方式,就可以直接引用外部的变量。
每轮循环启动一个协程,而协程启动与循环变量递增不是在同一个协程,协程启动的速度远小于循环执行的速度,所以即使是第一个协程刚起启动时,循环变量可能已经递增完毕。由于所有的协程共享循环变量i,而且这个i会在最后一个使用它的协程结束后被销毁,所以最后的输出结果都是循环变量的末值即2。

添加延时,确保协程启动:

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var wg sync.WaitGroup
	var m = []int{1, 2, 3}
	for i := range m {
		wg.Add(1)
		go func() {
			fmt.Print(i)
			wg.Done()
		}()
		time.Sleep(time.Second)
	}
	wg.Wait()

}

传入参数:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var m = []int{1, 2, 3}
	var wg sync.WaitGroup
	for i := range m {
		wg.Add(1)
 		go func(i int) {
			fmt.Print(i)
			wg.Done()
    	}(i)
	}
	wg.Wait()

}

局部变量:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var m = []int{1, 2, 3}
	var wg sync.WaitGroup
	for i := range m {
		wg.Add(1)
		n := i
		go func() {
			fmt.Print(n)
			wg.Done()
		}()
	}
	wg.Wait()
}

每次for的时候n都是不同的变量

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值