05 Jul 2017 10:39 +0000

预测以下代码的输出:

package main

import "fmt"

type student struct {
	Name string
	Age  int
}

func main() {
	m := make(map[string]*student)
	students := []student{
		{Name: "zhou", Age: 24},
		{Name: "li", Age: 23},
		{Name: "wang", Age: 22},
	}
	for _, stu := range students {
		m[stu.Name] = &stu
	}
	fmt.Println(m["li"].Age)
}

实际结果是:

22

这显然不是以上代码的预期结果, 原因在于遍历 students 的过程中, 变量 stu 仅在 for 循环开始时进行了一次内存分配, 在循环过程中依次被赋值为 students 的各个值, 而非在每一次重新声明. 因此, 以指针形式引用 stu 将始终指向同一位置, 这个位置在循环结束时值为 student{"wang", 22}, 以上代码的输出结果就显而易见了.

清楚原因后, 解决这样的问题就非常简单, 只要在循环体中为每一次循环单独声明一个变量即可:

func main() {
	// ...
	for _, stu := range students {
		temp := stu
		m[stu.Name] = &temp
	}
}

注意要以传值形式重新声明, 而不是引用形式!

REFERENCE

Golang range and pointers


Loading comments...