本文主要回顾一下Slice实现的使用和基本原理编程
源码包中 src/runtime/slice.go:slice 定义了Slice的数据结构: array指针指向底层数组,len表示切片长度,cap表示底层数组容量。数组
type slice struct { array unsafe.Pointer len int cap int }
该Slice长度为5,便可以使用下标slice[0] ~ slice[4]来操做里面的元素,capacity为10,表示后续向 slice添加新的元素时能够没必要从新分配内存,直接使用预留内存便可。数据结构
使用数组来建立Slice时,Slice将与原数组共用一部份内存。 例如,语句 slice := array[5:7] 所建立的Slice,结构以下图所示:app
切片从数组array[5]开始,到数组array[7]结束(不含array[7]),即切片长度为2,数组后面的内容都做为切 片的预留内存,即capacity为5。函数
使用append向Slice追加元素时,若是Slice空间不足,将会触发Slice扩容,扩容实际上从新一配一块更大的内 存,将原Slice数据拷贝进新Slice,而后返回新Slice,扩容后再将数据追加进去。性能
例如,当向一个capacity为5,且length也为5的Slice再次追加1个元素时,就会发生扩容,以下图所示:指针
扩容操做只关心容量,会把原Slice数据拷贝到新Slice,追加数据由append在扩容结束后完成。上图可见,扩容后 新的Slice长度仍然是5,但容量由5提高到了10,原Slice的数据也都拷贝到了新Slice指向的数组中。code
扩容容量的选择遵循如下规则: 若是原Slice容量小于1024,则新Slice容量将扩大为原来的2倍;
若是原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍; 使用append()向Slice添加一个元素的实现步骤以下:blog
使用copy()内置函数拷贝两个切片时,会将源切片的数据逐个拷贝到目的切片指向的数组中,拷贝数量取两个切片长度的最小值。内存
例如长度为10的切片拷贝到长度为5的切片时,将会拷贝5个元素。 也就是说,copy过程当中不会发生扩容。
跟据数组或切片生成新的切片通常使用 slice := array[start:end] 方式,这种新生成的切片并无指定切片的容量, 实际上新切片的容量是从start开始直至array的结束。
好比下面两个切片,长度和容量都是一致的,使用共同的内存地址:
sliceA := make([]int, 5, 10) sliceB := sliceA[0:5]
根据数组或切片生成切片还有另外一种写法,即切片同时也指定容量,即slice[start🔚cap], 其中cap即为新 切片的容量,固然容量不能超过原切片实际值,以下所示:
sliceA := make([]int, 5, 10) //length = 5; capacity = 10 sliceB := sliceA[0:5] //length = 5; capacity = 10 sliceC := sliceA[0:5:5] //length = 5; capacity = 5
这切片方法不常见,在Golang源码里可以见到,不过很是利于切片的理解。
《go专家编程》