最近做的项目都是golang的,虽然有C++的底子上手很快,但是还是会有一些小细节的地方需要注意。
上周就遇到了一个重复推送消息的bug,仔细查阅代码后发现是for循环的临时变量的地址被传入了函数中处理。
具体可见下面的代码片段,这段代码的运行结果是随机的。因为协程调用的时候主线程运行到for循环的什么地方是随机的,从而导致闭包内局域变量stu的值已经被修改,并不是想要的值。
代码片段
type student struct {
name string
age int
}
func show(students *student) {
fmt.Print(students.name + " ")
}
func main() {
stus := []student{}
for i := 0; i < 100; i++ {
stus = append(stus, student{name: "stu" + strconv.Itoa(i), age: i})
}
for _, stu := range stus {
go show(&stu)
}
time.Sleep(1 * time.Second)
}
正确的处理方法应该在循环内拷贝一份stu,然后传给show函数。这样{}内形成一个闭包,stuTm***保留到协程调用。
func main() {
stus := []student{}
for i := 0; i < 100; i++ {
stus = append(stus, student{name: "stu" + strconv.Itoa(i), age: i})
}
for _, stu := range stus {
stuTmp := stu
go show(&stuTmp)
}
time.Sleep(1 * time.Second)
}