go - 循环指针
问题描述
请考虑片段https://play.golang.org/p/GnhA1Tgw4sz,这是我遇到的问题的简化版本。我最初的问题是尝试将 UDP 消息发送到数组中的目的地,我注意到均匀分布的问题。
另外,代码:
package main
import (
"fmt"
"time"
)
var (
dests = [...]string{"word1", "word2", "word3", "word4", "word5", "word6", "word7", "word8"}
)
func main() {
fmt.Println("Hello!")
fmt.Println("dests", dests)
for _, dest := range dests {
fmt.Println("dest is", dest)
go func(dest_ptr *string) {
fmt.Println("Trying", *dest_ptr, dest_ptr)
}(&dest)
}
time.Sleep(200 * time.Second)
}
当我跑步时,
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
Trying word8 0x40c140
请注意,我一直在打word8
,可能是因为&dest
被覆盖了。我知道没有指针我不会有这个问题,正如 demo'd @ https://play.golang.org/p/ZD9JIuvdypJ。
我想使用指针,因为我原来的问题需要它。实现这一目标的正确方法是什么?
来自 C,这是一个很好的问题!据我所知,Go 不会为每次迭代创建一个新变量,这可能会在未来得到修复。
这是两种解决方法,
$ cat fixa.go
package main
import (
"fmt"
"time"
)
var (
dests = [...]string{"word1", "word2", "word3", "word4", "word5", "word6", "word7", "word8"}
)
func main() {
fmt.Println("Hello!")
fmt.Println("dests", dests)
for i := range(dests){
go func(dest_ptr * string){
fmt.Println("Handling", * dest_ptr, dest_ptr)
}(&dests[i])
}
time.Sleep(200 * time.Second)
}
和,
$ cat fixb.go
package main
import (
"fmt"
"time"
)
var (
dests = [...]string{"word1", "word2", "word3", "word4", "word5", "word6", "word7", "word8"}
)
func main() {
fmt.Println("Hello!")
fmt.Println("dests", dests)
for _, dest := range dests {
dest := dest // create a new variable, using a declaration style that may seem odd but works fine in Go:
go func(dest_ptr *string) {
fmt.Println("Trying", *dest_ptr, dest_ptr)
}(&dest)
}
time.Sleep(200 * time.Second)
}
解决方案
问题中的代码将局部变量的地址传递dest
给 goroutine。此局部变量在循环的每次迭代中设置。
通过将数组元素的地址传递给 goroutine 来修复:
for i := range dests {
fmt.Println("dest is", dests[i])
go func(dest_ptr *string) {
fmt.Println("Trying", *dest_ptr, dest_ptr)
}(&dests[i])
}
另一种方法是在循环的每次迭代中创建一个变量:
for _, dest := range dests {
dest := dest // <-- create new variable inside the loop
fmt.Println("dest is", dest)
go func(dest_ptr *string) {
fmt.Println("Trying", *dest_ptr, dest_ptr)
}(&dest)
}
推荐阅读
- r - 使用字符向量来引用和修改其他对象
- javascript - Javascript - 将映射数据分组
- python - 如何使用键盘中的输入关键字将光标从一行编辑移动到另一行编辑
- ionic-framework - 向 Ionic v4 应用程序添加高图指标时遇到问题
- c# - 在 Razor 页面中指定 ASP.NET Core 2 本地化程序的语言
- shared-libraries - 修改已编译共享库中符号的可见性
- nlp - 为什么在 first attention 论文中没有使用词嵌入(Glove、word2vecetc)?
- android - 无法同时使用 Google Analytics 和 Firebase 依赖项
- javascript - onClick 函数在嵌套的 antd 卡片组件中不起作用
- javascript - Node.js:异步函数似乎不等待 for 循环中 Promise 的解析