当前位置: 首页 > article >正文

Golang的for循环变量和goroutine的陷阱,1.22版本的更新

先来看一段golang 1.22版本之前的for循环的代码

package main

import "fmt"

func main() {
	done := make(chan bool)

	values := []string{"chen", "hai", "feng"}

	for _, v := range values {
		fmt.Println("start")

		go func() {
			fmt.Println(v)
			done <- true
		}()

		fmt.Println("end")
	}

	for _ = range values {
		<-done
	}
}

运行结果

输出的都是最后的"feng"

在for循环体里,匿名函数和循环变量v形成了闭包。循环变量v只会创建一次,每次迭代都会更新。而且这样的写法会导致for循环结束后才执行goroutine代码,这时候变量v里保存的是最后一个值,所以这里会输出"feng"。

以下提供两种常用的正确写法

第一种方法是在匿名函数中添加参数val,每个val都会被独立计算并保存到goroutine的栈中,所以可以达到预期的结果

package main

import "fmt"

func main() {
	done := make(chan bool)

	values := []string{"chen", "hai", "feng"}

	for _, v := range values {
		fmt.Println("start")

		go func(val interface{}) {
			fmt.Println(val)
			done <- true
		}(v)

		fmt.Println("end")
	}

	for _ = range values {
		<-done
	}
}

此时的运行结果

第二种写法:在for循环体内定义新的变量。循环体内定义的变量在遍历的过程中是不共享的,所以可以达到期望的效果。

package main

import "fmt"

func main() {
	done := make(chan bool)

	values := []string{"chen", "hai", "feng"}

	for _, v := range values {
		fmt.Println("start")

		val := v
		go func() {
			fmt.Println(val)
			done <- true
		}()

		fmt.Println("end")
	}

	for _ = range values {
		<-done
	}
}

此时的运行结果

升级到最新版本1.22,同样的代码

package main

import "fmt"

func main() {
	done := make(chan bool)

	values := []string{"chen", "hai", "feng"}

	for _, v := range values {
		fmt.Println("start")

		go func() {
			fmt.Println(v)
			done <- true
		}()

		fmt.Println("end")
	}

	for _ = range values {
		<-done
	}
}

现在运行结果如下

在golang 1.22中,循环的每次迭代都会创建新的变量,有效避免了以往版本中常见的闭包陷阱,提高了代码的安全性。

另外,1.22之前的版本,for range仅支持array, slice, string, map, channel等类型,现在新增了interger类型,这意味着我们可以像这样写代码

package main

import "fmt"

func main() {
	for i := range 10 {
		fmt.Println(i)
	}
}

 


http://www.kler.cn/a/234278.html

相关文章:

  • Java面向对象高级2
  • 设计模式练习(一) 单例模式
  • Python数据类型(一):bool布尔类型
  • NAT网络工作原理和NAT类型
  • JVM详解:JVM的系统架构
  • 数据库SQL——连接表达式(JOIN)图解
  • 【Java万花筒】加速Java应用程序:探索性能优化的利器
  • python3创建虚拟环境venv
  • 猫头虎分享已解决Bug || Kubernetes Error: Pods ‘pod-name‘ Not Found
  • Go语言每日一练——链表篇(八)
  • 深入了解Redis:选择适用于你的场景的持久化方案
  • IAR报错:Error[Pa045]: function “halUartInit“ has no prototype
  • JVM 性能调优- 五种内存溢出(5)
  • 006集——where语句进行属性筛选——arcgis
  • 从零开始:用 Rust 编写你的第一个 Web 服务
  • python web 框架Django学习笔记
  • 服务器渲染(SSR)-前端框架
  • 前端架构: 脚手架开发流程中的难点梳理
  • 5G NR 频率计算
  • Maven进阶
  • 与AI对话:编写高效Prompt的指南
  • mysql8.0 正值表达式Regular expressions (sample database classicmodels _No.5)
  • 跳过mysql8.0密码重置密码 Shell脚本
  • 开源项目的三年,我的项目经历了哪些变化?
  • 9、Node.js的下载与安装配置
  • 2023年,跳槽了4家电源公司