Golang: 高效使用切片

前情提要

在日常开发中,切片最开始通常都是空的,长度为0,需要添加元素进去。
在切片元素数量较少情况下还好,如果切片元素数量过多,或者扩容速度太快,会导致频繁的切片扩容,频繁分配新的底层数组,降低切片添加元素的速度。
本博客整理几种常见的切片添加元素方式,而且都是针对刚初始化的空切片。

正文

1、append从0开始一个一个添加元素(不推荐)
特点:频繁扩容,频繁分配新的底层数组,效率低

func main() {
	numbers := make([]int, 0)
	for i := 0; i < 100; i++ {
		numbers = append(numbers, i)
	}
	fmt.Println(len(numbers), cap(numbers)) // 100 128
}

2、初始化切片len,通过索引添加元素(推荐)
特点:常用在已知切片长度的情况下,不需要扩容,效率高

func main() {
	numbers := make([]int, 100)
	for i := 0; i < 100; i++ {
		numbers[i] = i
	}
	fmt.Println(len(numbers), cap(numbers)) // 100 100
}

3、提前预估切片容量,初始化切片cap,append添加元素(推荐)
特点:常用在大致知道或已知切片长度范围情况下,预估容量,初始化切片len为0,cap为预估值,可以尽量减少扩容次数,减少底层数组的分配次数

func main() {
	numbers := make([]int, 0, 100)
	for i := 0; i < 100; i++ {
		numbers = append(numbers, i)
	}
	fmt.Println(len(numbers), cap(numbers)) // 100 100
}

4、初始化切片len,append添加元素(错误)
问题:初始化len后,前len个元素已经存在了,如果调用append函数添加元素,会在一堆默认值0后面添加元素,原本初始化的元素没有使用,占用空间还导致数据错误。 切记初始化len > 0后,不要使用append添加元素,要使用索引添加元素

func main() {
	numbers = make([]int, 100)
	fmt.Println(len(numbers), cap(numbers)) // 100 100
	numbers = append(numbers, 999)
	fmt.Println(numbers)                    // [0 0 ... 0 999]
	fmt.Println(len(numbers), cap(numbers)) // 101 224
}

其中容量224的由来,参考之前的切片扩容机制博客:Golang: 切片扩容机制源码分析
扩容前len=101,cap=100,期望容量为101 <= 当前容量100的2倍,当前容量为100 < 256,容量翻倍,扩容到容量为200
期望分配的内存为1600字节,class_to_size数组对齐内存后为1792字节,扩容后容量为224

你可能感兴趣的:(Golang,golang,开发语言,后端)