ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
slice是 Go 中的一种基本的数据结构,使用这种结构可以用来管理数据集合。但是slice本身并不是动态数据或者数组指针。slice常见的操作有 reslice、append、copy。 slice自身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。slice本身是一个只读对象,其工作机制类似数组指针的一种封装。 slice是对数组一个连续片段的引用,所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。 这里需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个与指向数组的动态窗口。 slice是可以看做是一个长度可变的数组。 slice数据结构如下: ~~~go type slice struct { array unsafe.Pointer len int cap int } ~~~ slice的结构体由3部分构成,Pointer 是指向一个数组的指针,len 代表当前切片的长度,cap 是当前切片的容量。cap 总是大于等于 len 的。 通常我们在对slice进行append等操作时,可能会造成slice的自动扩容。 其扩容时的大小增长规则是: * 如果切片的容量小于1024个元素,那么扩容的时候slice的cap就翻番,乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。 * 如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。 通过slice源码可以看到,append的实现只是简单的在内存中将旧slice复制给新slice. ~~~go newcap := old.cap if newcap+newcap < cap { newcap = cap } else { for { if old.len < 1024 { newcap += newcap } else { newcap += newcap / 4 } if newcap >= cap { break } } } ~~~