直接看代码:
package main
import "fmt"
func main() {
p := []person{
{name: "张三", city: "杭州", age: 18},
{"李四", "衢州", 16},
{"王五", "宁波", 20},
}
m := make(map[string]*person) //定义一个结构体map
mv := make(map[string]int) //定义一个int类型map
for k, v := range p {
fmt.Printf("v:=%p\n", &v) //每次地址的值都一样
fmt.Printf("k:=%p\n", &k) //每次地址的值都一样
m[v.name] = &v
mv[v.name] = v.age
}
for k, v := range mv {
fmt.Println(k, "--->", v)
}
for k, v := range m {
fmt.Println(k, "--->", v)
}
}
type person struct {
name string
city string
age int
}
结果为:
v:=0xc000062330
k:=0xc00000a0d8
v:=0xc000062330
k:=0xc00000a0d8
v:=0xc000062330
k:=0xc00000a0d8
王五 ---> 20
张三 ---> 18
李四 ---> 16
张三 ---> &{王五 宁波 20}
李四 ---> &{王五 宁波 20}
王五 ---> &{王五 宁波 20}
从结果来看,m的value值始终是 &{王五 宁波 20},但是mv的value又是正常的。这是为什么呢?
range每次都会把当前值赋值到循环变量上,而不是直接使用原变量,在例程中,我们保存了当前循环变量的地址,但是Go每次循环都会复用这一"循环变量"【也就是for里面的k,v只声明了一次,地址不会变】, 所以每次保存的地址实际上指向同一变量,最后,内容都变成了最后一个元素的值。所以m[v.name] = &v因为等号右边是地址,并且这个地址不变,自然存的都是最后一次的值了;mv[v.name] = v.age等号右边是一个int值而已,每次循环自然不一样
注:在使用for range的时候,要注意的是,不管是slice还是map,循环的值都是被range值拷贝出来的副本值【对应例子中的k,v都是从副本中取出来的值】
如果要修改只要把m[v.name] = &v改为m[v.name] = &p[k]就可以了
改了之后结果:
v:=0xc000062330
k:=0xc00000a0d8
v:=0xc000062330
k:=0xc00000a0d8
v:=0xc000062330
k:=0xc00000a0d8
张三 ---> 18
李四 ---> 16
王五 ---> 20
王五 ---> &{王五 宁波 20}
张三 ---> &{张三 杭州 18}
李四 ---> &{李四 衢州 16}