很多语言中都存在类似动态数组的概念,c++中的vector,Golang里的silce,都是类似动态数组概念。
silce的组成
go
// file: src/runtime/silce.gotype slice struct { array unsafe.Pointer len int cap int }从源码中可以看到,go中的silce结构体包含三个部分,array len cap.
array传入的是一个指针,用作silce的底层存储数组。len是silce的长度,cap则是底层数组的大小。
当silce的len逐渐逼近cap的时候(len达到cap的一半),将会触发扩容机制。
silce 的扩容
计算下一个cap
go
// nextslicecap computes the next appropriate slice length.func nextslicecap(newLen, oldCap int) int { newcap := oldCap doublecap := newcap + newcap if newLen > doublecap { return newLen } const threshold = 256 if oldCap < threshold { return doublecap } for { // Transition from growing 2x for small slices // to growing 1.25x for large slices. This formula // gives a smooth-ish transition between the two. newcap += (newcap + 3*threshold) >> 2 // We need to check `newcap >= newLen` and whether `newcap` overflowed. // newLen is guaranteed to be larger than zero, hence // when newcap overflows then `uint(newcap) > uint(newLen)`. // This allows to check for both with the same comparison. if uint(newcap) >= uint(newLen) { break } } // Set newcap to the requested cap when // the newcap calculation overflowed. if newcap <= 0 { return newLen } return newcap }go在设计的时候,对于不同旧cap做了不同的扩容机制。
当 旧cap < 256 时候,将会扩容到旧容量的两倍。
当 旧cap > 256 时候,将会扩容到旧容量的约1.25倍。
这个约1.25倍有点说法。
当大于256时候,newcap=oldcap+(oldcap + 3*256)/4
实际扩容是要比1.25倍稍微大一点的。这是为了使从2倍扩容逐渐过渡到1.25倍扩容。