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)
	}
}

 

相关推荐

  1. 深入理解Golanggoroutine

    2024-02-10 08:38:02       59 阅读
  2. 通过例子学习golangGoroutine

    2024-02-10 08:38:02       52 阅读
  3. golang大杀器协程goroutine

    2024-02-10 08:38:02       65 阅读
  4. 增强for循环for-each循环

    2024-02-10 08:38:02       25 阅读
  5. 【Go】goroutine并发常见变量覆盖案例

    2024-02-10 08:38:02       41 阅读
  6. Go语言中如何处理goroutine循环变量

    2024-02-10 08:38:02       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-10 08:38:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-10 08:38:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-02-10 08:38:02       87 阅读
  4. Python语言-面向对象

    2024-02-10 08:38:02       96 阅读

热门阅读

  1. itextpdf使用:使用PdfReader添加图片水印

    2024-02-10 08:38:02       55 阅读
  2. MyBatis-Plus 实现分页

    2024-02-10 08:38:02       48 阅读
  3. Lua metatable & metamethod

    2024-02-10 08:38:02       54 阅读
  4. 力扣热题100_双指针_283_移动零

    2024-02-10 08:38:02       60 阅读
  5. 力扣-260. 只出现一次的数字 III

    2024-02-10 08:38:02       46 阅读
  6. 2.8 假期作业

    2024-02-10 08:38:02       46 阅读