直接上一段代码,检测你的段位 1. 如果你预期的结果和运行后的结果一致,恭喜你已彻底get slice
2. 如果你看懂了运行结果,说明对slice的概念是理解的,只是掌握的不熟,缺乏实践
3. 如果看不懂运行结果,那么就认真听我的分析
func test_slice(){
arr :=[...]int{0,1,2,3,4,5,6,7}
// cap=8-6
var slice []int = arr[6:8:8]
// 请思考实际容量
fmt.Println(arr,slice,cap(slice))
slice[1]=50
//新slice2还与slice指向同一个数组吗
var slice2 []int = append(slice, 100)
//新slice3还与slice2指向同一个数组吗
var slice3 []int = append(slice2, 200)
//新slice4还与slice3指向同一个数组吗
var slice4 []int = append(slice3, 300)
slice3[1]=52
slice4[1]=20
fmt.Println("arr=",arr,"slice=",slice,"slice2=",slice2,"slice3=",slice3,"slice4=",slice4)
fmt.Println("内存地址:arr[1]=",&arr[7],"slice=",&slice[1],"slice2=",&slice2[1],"slice3=",&slice3[1],"slice4=",&slice4[1])
}
运行结果
[0 1 2 3 4 5 6 7] [6 7] 2
arr= [0 1 2 3 4 5 6 50] slice= [6 50] slice2= [6 52 100] slice3= [6 52 100 200] slice4= [6 20 100 200 300]
内存地址:arr[1]= 0xc000092038 slice= 0xc000092038 slice2= 0xc00008e048 slice3= 0xc00008e048 slice4= 0xc000092088
分析
1.slice的基础概念,请参考官方的文档,slice是一个引用类型,为动态扩容数组而生。slice的底层是指向的某个数组的指针引用。如果改变slice,其实就是在改变slice所指向的数组的值
2.slice如果直接指定指向已存在的数组,那么容量不能超过你所指向的数组的索引的后续的长度,所以设置不能超过8(len(arr)),而slice实际容量是2
3.slice每次被append,都会在原来slice尾端增加一个值,并且生成新的slice(slice地址不一样了)
4.slice的扩容是2倍扩容,每次扩容都是生成一个新数组,并且复制原来的值。注意未超过容量的append操作不会改变slice指向的数组,否则会扩容并且指向新的数组
5.基于第4点描述,所以slice2已经不和slice指向同一个数组了,因为超过了容量2,此时slice2已经是扩容2*2=4
6.因为slice2已经是cap=4,所以slice3依然在容量内,所以slice3依然和slice2指向同一个扩容后的数组,因此改变slice3[1] =52,slice2[1]也会跟着改变
7.slice3时,cap=4已经被用完,此时再append操作,此时又要扩容了,4*2=8,所以slice4指向了新数组,因此改变slice4[1]=20,已经与前面的slice毫无关联了
综上
体现了slice cap容量知识、指向特点、扩容机制,扩容后的变化
如果看不懂,那么一定要认真看array和slice的知识点,看懂了,再来做我发的练习。你就融会贯通了