您现在的位置是:亿华云 > 应用开发
Go 语言使用 goroutine 运行闭包的“坑”
亿华云2025-10-03 20:25:32【应用开发】5人已围观
简介1.介绍在 Go 语言中,函数支持匿名函数,闭包就是一种特殊的匿名函数,它可以用于访问函数体外部的变量。需要注意的是,在for ... range ...中,使用 goroutine 执行闭包时,经
在 Go 语言中,坑函数支持匿名函数,语言e运闭包就是使用一种特殊的匿名函数,它可以用于访问函数体外部的行闭变量。
需要注意的坑是,在 for ... range ... 中,语言e运使用 goroutine 执行闭包时,使用经常会掉“坑”。行闭
因为匿名函数可以访问函数体外部的坑变量,而 for ... range ... 返回的语言e运 val 的值是引用的同一个内存地址的数据,所以匿名函数访问的使用函数体外部的 val 值是循环中最后输出的一个值。源码库
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=%p\n", 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=%p\n", 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
很赞哦!(98283)
相关文章
- 域后缀首选.com,.net,然后是.cn。后缀选择不当,导致流量损失。域名是企业与互联网网址之间的链接,关键是企业在网络上存在的标志。因此,选择好域名是开展网上工作的首要重要条件。
- 想要注册域名要符合什么条件?新手应该做好什么准备?
- 面对域名投资需要知晓什么?域名投资有什么看法?
- 想要注册域名有哪些流程?新手流程要知道什么?
- 域名资源有限,好域名更是有限,但机会随时都有,这取决于我们能否抓住机会。一般观点认为,国内域名注册太深,建议优先考虑外国注册人。外国注册人相对诚实,但价格差别很大,从几美元到几十美元不等。域名投资者应抓住机遇,尽早注册国外域名。
- 域名解析怎么弄?新手对解析域名了解什么步骤?
- 注册域名要做到哪几点?小白域名注册要注意什么?
- 新手知道的选择域名技巧有哪些?该怎么做?
- 二、如何选择合适的域名
- 新手怎么看待老域名的?老域名做网站有什么风险?