分享|Golang for内使用指针的细节
422
2024.10.25
2024.10.25
发布于 中国

背景

最近做的项目都是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)
}
评论 (2)