先上代码:

func TestSlice2(t *testing.T) {
	e := []int32{1, 2, 3}
	fmt.Println("cap of e before:", cap(e))
	e = append(e, 4, 5, 6, 7)
	fmt.Println("cap of e after:", cap(e))
}

关于上述代码的输出,如果按照网上大规模流传的说法会按以下规则进行扩容(基于Go 1.18):

新扩容容量>当前容量的2倍旧容量< 256旧容量≥ 256初始容量为 0

源码如下:

// go 1.18 src/runtime/slice.go:178
func growslice(et *_type, old slice, cap int) slice {
    // ……
    newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		const threshold = 256
		if old.cap < threshold {
			newcap = doublecap
		} else {
			for 0 < newcap && newcap < cap {
                // 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) / 4
			}
			if newcap <= 0 {
				newcap = cap
			}
		}
	}
	// ……

}
cap
=== RUN   TestSlice2
cap of e before: 3
cap of e after: 8
--- PASS: TestSlice2 (0.00s)
PASS


Process finished with the exit code 0

容量实际上会是 8,这是为什么呢?

growsliceroundupsizenewcap
capmem = roundupsize(uintptr(newcap) * ptrSize)
newcap = int(capmem / ptrSize)
ptrSizenewcaproundupsize7 * 8 = 56roundupsize
func roundupsize(size uintptr) uintptr {
	if size < _MaxSmallSize {
		if size <= smallSizeMax-8 {
			return uintptr(class_to_size[size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]])
		} else {
			//……
		}
	}
    //……
}

部分变量值:

const _MaxSmallSize = 32768
const smallSizeMax = 1024
const smallSizeDiv = 8

var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31}

var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536, 1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}
roundupsizeuintptr(class_to_size[size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]])
(size+smallSizeDiv-1)/smallSizeDiv = (56 + 8 - 1) / 8 = 7size_to_class8[7] = 5class_to_size[5] = 64
roundopsizenewcap = int(capmem / ptrSize) = int(64 / 8) = 8

如果文章对您有所帮助,别忘了点赞收藏哦~