package main
import "fmt"
func main() {
slice := []int{1, 2}
fmt.Printf("data:%v, len:%d, cap:%dn", slice, len(slice), cap(slice))
updateslice(slice)
fmt.Printf("after data:%v, len:%d, cap:%dn", slice, len(slice), cap(slice))
}
func updateslice(slice []int) {
slice[0] = 12
slice = Append(slice, 10)
fmt.Printf("inner data:%v, len:%d, cap:%dn", slice, len(slice), cap(slice))
}
执行结果为:
data:[1 2], len:2, cap:2
after data:[12 2], len:2, cap:2
由于切片是引用类型,所以数据修改会影响外部,实际上内外是指向同一个底层数据。但是当对updateslice函数做append操作后,指向结果为:
data:[1 2], len:2, cap:2
inner data:[12 2 10], len:3, cap:4
after data:[12 2], len:2, cap:2
发现内部的添加数据修改并没有影响到外部变量,此时可以看到内部的切片容量发生了扩容,之前的数据会被copy一份到新的地址,此时该扩容后的切片指向的是新的地址,函数内外切片并不是指向同一个底层数据。
总结:当数据调整发生扩容时,内外切片不是指向同一个底层数据;否则,指向同一个底层数组。
type student struct {
name string
age int
}
func main() {
m := make(map[string]*student)
stus := []student{
{name: "小王子", age: 18},
{name: "娜扎", age: 23},
{name: "大王八", age: 9000},
}
// 这里出现问题
for _, stu := range stus {
m[stu.name] = &stu
}
for k, v := range m {
fmt.Println(k, "=>", v.name)
}
}
对于该代码,我们的预期结果是
娜扎 => 娜扎
大王八 => 大王八
小王子 => 小王子
但是得到的结果是:
小王子 => 大王八
娜扎 => 大王八
大王八 => 大王八
原因是 for遍历时,变量stu是值的副本,每次遍历仅进行struct值拷贝,它指向的地址不变,所以每一次操作m[stu.name] = &stu,实际指向的都是同一个地址,遍历完成后,存储的是结构体最后一个值的拷贝。根本原因在于for-range会使用同一块内存去接收循环中的值。
应取切片中原始值的指针,修改如下:
for _, stu := range stus {
value := stu
m[stu.name] = &value
}