Golang中有多种变量类型,,值类型,引用类型,指针类型.每个类型作为参数传入都会有不同的结果
值类型无法被函数内部修改
引用类型和指针类型可以从函数内部修改变量
Slice是引用类型
在学习<<Go专家编程>>过程中,遇到这样一个题
func SliceRise(s []int) {
s = append(s, 0)
for i := range s {
s[i]++
}
}
func SliceRiseTest() {
s1 := []int{1, 2}
s2 := s1
s2 = append(s2, 3)
SliceRise(s1)
SliceRise(s2)
fmt.Println(s1, s2)
}
大家可以尝试看看打印输出什么
输出打印:
[1,2] [2,3,4]
下面来解释解释为什么会输出这样一个结果
首先s1 -> len:2 cap:2
s2:=s1 此时s2,s1可以说完全一致,,,指向同一片内存空间
但是当 s2 = append(s2, 3)
s2发生了扩容,,为s2分配新的内存空间地址
此时 s1 -> len:2 cap:2 s1 -> len:3 cap:4
当执行SliceRise(s1)时
SliceRise内部得到一个s1的拷贝切片s,array指向相同的内存地址复制len,cap,进行append的操作,, s = append(s, 0) 这步操作后s -> len:3 > cap:2, 开辟新的内存空间,将新的内存地址赋给拷贝切片s,但是s1本身并没有被修改,所以后面的操作是对拷贝切片s(新开辟的内存空间)进行操作,无法对s1有影响,所以打印s1 :[1,2]
当执行SliceRise(s2)时,引用传递s2
SliceRise内部得到一个s2的拷贝切片s,array指向相同的内存地址,复制len,cap,进行append的操作,,,但array内存够用,此时s - >len:4,cap:4,,,所需后续进行对s进行的操作就相当于对s2进行的操作,,因为他们的底层数据地址是一样的.但是打印出来 s2: [2,3,4]
Slice结构体有三个字段
len和cap为值类型,array为引用类型,,,值类型无法从函数内部修改,,所以函数内部为4,4,,但是外部依旧为3,4
所以array依旧修改了,但是len相对内部,外部并没有被修改依旧是3,,也就是修改对于函数外部是无法被观测到的
我们可以尝试看看这个s2[3]这个位置是否依旧添加相应的元素,,代码如下
func SliceRise(s []int) {
fmt.Printf("append before arr: %p\n", s)
s = append(s, 0)
fmt.Printf("append after arr: %p\n", s)
for i := range s {
s[i]++
}
}
func SliceRiseTest() {
s1 := []int{1, 2}
s2 := s1
s2 = append(s2, 3) //s2 与 s1 内存地址不在相同
fmt.Printf("SliceRise Before s1: %p\n", s1)
fmt.Printf("SliceRise Before s2: %p\n", s2)
SliceRise(s1)
SliceRise(s2)
fmt.Printf("SliceRise After s1: %p\n", s1)
fmt.Printf("SliceRise After s2: %p\n", s2)
fmt.Println(s1, s2)
s3 := s2[0:4]
fmt.Println(s3)
}
输出结果
哈哈,只是个人学习的一些见解,,,如有问题或者错误,请大家指正!