Go学习笔记 由数组和切片 引发的值类型和引用类型的思考
先看如下代码, 看看运行结果如何:
func main() { var c = [3]int{1, 2, 3} //定义一个长度为3的int类型的数组 d := c //将数组c赋值给d d[1] = 100 //修改数组d中索引为1的值为100 fmt.Printf("c的值是%v,c的内存地址是%p\n", c, &c) //c的值是[1 2 3],c的内存地址是0xc42000a180 fmt.Printf("d的值是%v,d的内存地址是%p\n", d, &d) //d的值是[1 100 3],d的内存地址是0xc42000a1a0 var a = []int{1, 2, 3, 4, 5} //creates and array and returns a slice reference b := a //此时a,b都指向了内存中的[1 2 3 4 5]的地址 b[1] = 10 //相当于修改同一个内存地址,所以a的值也会改变 fmt.Printf("a的值是%v,a的内存地址是%p\n", a, &a) //a的值是[1 10 3 4 5],a的内存地址是0xc42000a180 fmt.Printf("b的值是%v,b的内存地址是%p\n", b, &b) //b的值是[1 10 3 4 5],b的内存地址是0xc42000a1a0 }
运行结果:
D:\GoProject\src\main>go run main.go c的值是[1 2 3],c的内存地址是0xc000190020 d的值是[1 100 3],d的内存地址是0xc000190040 a的值是[1 10 3 4 5],a的内存地址是0xc0001840a0 b的值是[1 10 3 4 5],b的内存地址是0xc0001840c0
至于原因 注释已经解释了, c是数组 值类型,a是切片引用类型。 来看看他们忘得的一些介绍吧:
官方的 Blog 中有写:
Map types are reference types, like pointers or slices, ...
Map types are reference types, like pointers or slices, ...
这边说 Map 类型是引用类型,像是指针或是 Slice(切片)。所以我们基本上可以把它当作是指针来看待(注意,只是近似,或者说其中含有指针,其内部仍然含有其他信息,这里只是为了便于理解),只不过这个指针有些特殊罢了。
m1 中,当调用 mdMap 方法时重新开辟了内存,将 m 的内容,也就是 map 的地址拷贝入了 m',所以此时当操作 map 时,m 和 m' 所指向的内存为同一块,就导致 m 的 map 发生了改变。
而在 m2 中,在调用 mdMap 之前,m 并未分配内存,也就是说并未指向任何的 map 内存区域。从未导致 m' 的 map 修改不能反馈到 m 上。