会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 Go 语言使用 goroutine 运行闭包的“坑”!

Go 语言使用 goroutine 运行闭包的“坑”

时间:2025-11-03 17:10:20 来源:益强数据堂 作者:应用开发 阅读:863次
​1.介绍

在 Go 语言中,坑函数支持匿名函数,语言e运闭包就是使用一种特殊的匿名函数,它可以用于访问函数体外部的行闭变量。

需要注意的坑是,在 for ... range ... 中,语言e运使用 goroutine 执行闭包时,使用经常会掉“坑”。行闭

Go 语言使用 goroutine 运行闭包的“坑”

因为匿名函数可以访问函数体外部的坑变量,而 for ... range ... 返回的语言e运 val 的值是引用的同一个内存地址的数据,所以匿名函数访问的使用函数体外部的 val 值是循环中最后输出的一个值。WordPress模板

2 .“踩坑”示例代码func main() {

done := make(chan bool)

values := []string{"a",行闭 "b", "c"}

for _, v := range values {

go func() {

fmt.Println(v)

done <- true

}()

}

// wait for all goroutines to complete before exiting

for _ = range values {

<-done

}

}

输出结果:

c

c

c

阅读上面这段代码,在 for ... range ... 中,坑使用 goroutine 执行闭包,语言e运打印切片中的使用元素,实际输出结果不是我们期望得到的输出结果。

这是因为循环的每次迭代都使用相同的变量 v 实例,因此每个闭包共享该单个变量。我们可以在示例代码中简单修改,同时输出变量 v 的内存地址和值。

把 fmt.Println(v)​ 修改为 fmt.Printf("val=%s pointer=%p\n", v, &v)。

修改后的输出结果:

val=c pointer=0xc000010200

val=c pointer=0xc000010200

val=c pointer=0xc000010200

我们可以在输出结果中发现,打印变量 v 的内存地址都是 0xc000010200。

当闭包运行时,它会在执行 fmt.Println​ 时打印变量 v 的值,源码库但 v 的值可能在 goroutine 启动后已被修改。感兴趣的读者朋友们可以使用 go vet 检查。

怎么避免“踩坑”呢?

一种方法是将变量作为参数传递给闭包:

func main() {

done := make(chan bool)

values := []string{"a", "b", "c"}

for _, v := range values {

go func(param string) {

// fmt.Println(v)

fmt.Printf("val=%s pointer=%pn", param, ¶m)

done <- true

}(v)

}

// wait for all goroutines to complete before exiting

for _ = range values {

<-done

}

}

输出结果:

val=c pointer=0xc000010200

val=a pointer=0xc00009a000

val=b pointer=0xc0000a4000

阅读上面这段代码,通过将变量 v 的值作为参数传递给闭包,然后,该值作为形参 param 的值,在函数体内部被访问。

另外一种方法是创建一个新变量:

func main() {

done := make(chan bool)

values := []string{"a", "b", "c"}

for _, v := range values {

param := v

go func() {

// fmt.Println(v)

fmt.Printf("val=%s pointer=%pn", param, ¶m)

done <- true

}()

}

// wait for all goroutines to complete before exiting

for _ = range values {

<-done

}

}

输出结果:

val=c pointer=0xc000082200

val=a pointer=0xc0000821e0

val=b pointer=0xc0000821f0

通过输出结果可以发现,该种方式也可以达到我们期望的结果。

3.总结

本文我们介绍了在 for ... range ... 中,Go 语言在每次迭代时,没有定义一个新变量,导致使用 goroutine 运行闭包时,经常会掉“坑”。

我们给出避免“踩坑”的两种方法,其中,第二种方法更简单。网站模板

参考资料:

https://go.dev/tour/moretypes/25

https://gobyexample.com/closures

https://pkg.go.dev/cmd/vet

https://go.dev/doc/faq#closures_and_goroutines

https://go.dev/doc/effective_go#goroutines

(责任编辑:数据库)

推荐内容
  • 从零开始学习服装电脑排版教程(手把手教你成为服装电脑排版新手)
  • 电脑重装系统XP系统教程(详细步骤和技巧,让你轻松重装系统)
  • 黑鲨u盘一键重装系统教程(简单易行的黑鲨u盘一键重装系统方法)
  • 使用U盘重装Win7系统的详细教程(简单易懂的步骤让您快速重装Win7系统)
  • 微星450主板装机教程(全面解析微星450主板的安装和配置)
  • 使用U盘重装Win7系统的详细教程(简单易懂的步骤让您快速重装Win7系统)