要想更好的了解一个知识点,实战是最好的经历。
题目
我这里放一道题目:
package mainimport "fmt"func SliceRise(s []int) {s = append(s, 0)for i := range s {s[i]++}fmt.Println(s)
}func SlicePrint() {s1 := []int{1, 2}s2 := s1s2 = append(s2, 3)SliceRise(s1)SliceRise(s2)fmt.Println(s1, s2)
}func main() {SlicePrint()
}
大家猜猜本题的运行结果是多少?
s1: 1、2 || s2:2、3、4
知识点
是不是蒙了( •̀ ω •́ )✧,蒙了才有效果,才能更加明白自己的不足。
以上涉及了好几个知识点。我一一讲起。
1、切片的底层数据结构
type Slice struct{array unsafe.Pointer // 储存着数组存放地址len int // 切片长度cap int // 切片容量
}
切片的底层数据结构是一个 “结构体"
2、切片的扩容机制
slice的扩容遵循以下原则
1、如果slice容量小于1024,则新slice容量扩大为原来的2倍。
2、如果slice容量大于等于1024,采用1.25倍,则新的slice容量将扩大为原来的1.25倍
这里有一点需要注意,当slice扩容时,会开辟一个新的空间,将旧的slice依次复制进入。
学到这里,其实就已经基本OK了,接下来我会放出本题的解析。
解析
大家都知道,切片是引用传递。什么是引用传递呢?就是传递地址值。
但是有一点需要注意,切片的数据结构是结构体,底层是struct。
所以传递时,将会创造一个新的结构体,把老结构体全部粘贴复制进去(地址,len、cap)
s1 := s2
如上,就相当于
相当于把两个结构体,直接复制并拷贝过去复制了一个一模一样的。
显而易见,这两个,是不同的结构体。--> 但是却共同一个共同的地址0111,也就是同一个数组。
到这里大家应该就明白了,他们传递时,传递的是地址。结构体是直接复制过去的一个新的。
s = append(s,0)时,由于新添加了一个值,导致容量扩大,cap增加。这时就会分配一个新地址给s结构体。而原来的s1结构体内,存的地址不会改变。
故fmt.Println(s1)是:1、2。
而s2,用同样的分析,亦可得出结论。