go中for range的坑以及解决方案

一、for range的坑

相信小伙伴都遇到过以下的循环变量的问题,那是因为循环的val变量是重复使用的,即仅有一份。也就是说,每次循环后赋给val的值就会把前面循环赋给val的值替换掉,所以打印出来的值都是最后一次循环赋给val的值。

1、例子

Go 复制代码
func fr1() {
	arr := []int{1, 2, 3}
	for _, val := range arr {
		go func() {
            time.Sleep(time.Millisecond * 100)
			fmt.Println(val)
		}()
	}
	time.Sleep(time.Second)
}
//输出结果:3 3 3 


func fr2() {
	arr := [2]int{1, 2}
	arrnew := []*int{}
	for _, val := range arr {
		arrnew = append(arrnew, &v)
	}

	fmt.Println(*arrnew[0], *arrnew[1])
	//输出结果: 2 2
}

2、解决方案

使用局部变量/临时变量,即可解决

Go 复制代码
func fr1() {
	values := []int{1, 2, 3, 4, 5}
	for _, val := range values {
        //在这加入临时变量
		val := val 
		go func() {
			time.Sleep(time.Millisecond * 100)
			fmt.Println(val)
		}()
	}
	time.Sleep(time.Second)
}
//输出结果:2 3 1 4 5 或 5 3 4 1 2 等无序结果


//===========================或者=============================

func fr1() {
	values := []int{1, 2, 3, 4, 5}
	for _, val := range values {
        //传入变量
		go func(val int) {
			time.Sleep(time.Millisecond * 100)
			fmt.Println(val)
		}(val)
	}
	time.Sleep(time.Second)
}
//输出结果:2 3 1 4 5 或 5 3 4 1 2 等无序结果

二、官方解决方案

1、在Go1.21版本中,提前体验

可以设置GOEXPERIMENT=loopvar ,就会解决以上问题,运行代码时就不会出现以上的坑。

Windows中设置举例

bash 复制代码
go env -w GOEXPERIMENT=loopvar
或
$env:GOEXPERIMENT="loopvar"
bash 复制代码
> go env
set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\Administrator\AppData\Local\go-build
set GOENV=C:\Users\Administrator\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=loopvar
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\Administrator\go\pkg\mod

2、预计在 Go1.22 起,在go.mod中支持

新的 for 循环语义,将会在 go.mod 文件中的 go 行(版本声明大于等于 Go1.22 下)默认应用**。** 也就不用设置GOEXPERIMENT=loopvar

相关推荐
FastBean3 分钟前
BizAssert:一个轻量级、生产就绪的 Java 业务断言工具类
java·后端
疯狂的程序猴7 分钟前
iOS 多技术栈混淆实现,跨平台 App 混淆拆解与组合
后端·ios
是Smoky呢18 分钟前
springAI+向量数据库+RAG入门案例
java·开发语言·ai编程
法欧特斯卡雷特37 分钟前
从 Kotlin 编译器 API 的变化开始: 2.3.20
android·后端·开源
Java水解1 小时前
一篇文章让你彻底弄懂Spring Boot 自动配置原理详解
spring boot·后端
_Twink1e1 小时前
[算法竞赛]九、C++标准模板库STL常用容器大全
开发语言·c++
Java水解1 小时前
【MYSQL】MYSQL学习的一大重点:MYSQL数据类型
后端·mysql
架构师沉默1 小时前
为什么 Dubbo 从 ZooKeeper 转向 Nacos?
java·后端·架构
用户8307196840821 小时前
Spring Prototype Bean的四种正确使用方式
java·spring boot·后端
代码丰1 小时前
一篇讲透:Spring Boot + Redisson + 注解 + AOP 实现接口限流(可直接落地)
后端