Golang 理解slice 特性- 容量 指针 扩容

直接上一段代码,检测你的段位
        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的知识点,看懂了,再来做我发的练习。你就融会贯通了

猜你喜欢

转载自blog.csdn.net/m0_37298500/article/details/121991153
今日推荐