本篇内容主要讲解“go的切片扩容机制是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“go的切片扩容机制是什么”吧!
切片的扩容策略?如何扩容?
扩容策略:如果切片的容量小于 1024 个元素,于是扩容的时候就翻倍增加容量。总容量从原来的1个翻倍到现在的2个。
一旦元素个数超过 1024 个元素,那么增长因子就变成 1.25 ,即每次增加原来容量的四分之一。
注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的。
举一个扩容策略例子:
func main() { slice := []int{10, 20, 30, 40} newSlice := append(slice, 50) fmt.Printf("Before slice = %v, Pointer = %p, len = %d, cap = %d ", slice, &slice, len(slice), cap(slice)) fmt.Printf("Before newSlice = %v, Pointer = %p, len = %d, cap = %d ", newSlice, &newSlice, len(newSlice), cap(newSlice)) newSlice[1] += 10 fmt.Printf("After slice = %v, Pointer = %p, len = %d, cap = %d ", slice, &slice, len(slice), cap(slice)) fmt.Printf("After newSlice = %v, Pointer = %p, len = %d, cap = %d ", newSlice, &newSlice, len(newSlice), cap(newSlice)) } // result Before slice = [10 20 30 40], Pointer = 0xc4200b0140, len = 4, cap = 4 Before newSlice = [10 20 30 40 50], Pointer = 0xc4200b0180, len = 5, cap = 8 After slice = [10 20 30 40], Pointer = 0xc4200b0140, len = 4, cap = 4 // 相加的数是在新的切片上相加的 After newSlice = [10 30 30 40 50], Pointer = 0xc4200b0180, len = 5, cap = 8
从结果我们可以看出,新切片和之前的切片已经不同了,因为新的切片更改了一个值,并没有影响到原来的数组,新切片指向的数组是一个全新的数组,并且cap容量也发生了变化。
那么到底是新数组还是老数组呢?
扩容之后数组就一定是新的吗?其实是分两种情况。
第一种情况:
func main() { array := [4]int{10, 20, 30, 40} slice := array[0:2] newSlice := append(slice, 50) fmt.Printf("Before slice = %v, Pointer = %p, len = %d, cap = %d ", slice, &slice, len(slice), cap(slice)) fmt.Printf("Before newSlice = %v, Pointer = %p, len = %d, cap = %d ", newSlice, &newSlice, len(newSlice), cap(newSlice)) newSlice[1] += 10 fmt.Printf("After slice = %v, Pointer = %p, len = %d, cap = %d ", slice, &slice, len(slice), cap(slice)) fmt.Printf("After newSlice = %v, Pointer = %p, len = %d, cap = %d ", newSlice, &newSlice, len(newSlice), cap(newSlice)) fmt.Printf("After array = %v ", array) } // result Before slice = [10 20], Pointer = 0xc4200c0040, len = 2, cap = 4 Before newSlice = [10 20 50], Pointer = 0xc4200c0060, len = 3, cap = 4 After slice = [10 30], Pointer = 0xc4200c0040, len = 2, cap = 4 After newSlice = [10 30 50], Pointer = 0xc4200c0060, len = 3, cap = 4 After array = [10 30 50 40]
通过这个结果可以明显的看出,修改新切片的值居然影响到了老切片的值了,扩容以后并没有新建一个新的数组,并且append操作也改变了原来数组的值,如果原数组上有多个切片,那么这些切片都会影响,产生了莫名的bug!
这种情况也极容易出现在字面量创建切片时候,第三个参数 cap 传值的时候,如果用字面量创建切片,cap 并不等于指向数组的总容量,那么这种情况就会发生。
注意:建议用字面量创建切片的时候,cap 的值一定要保持清醒,避免共享原数组导致的 bug。
第二种情况:
第二种情况就是扩容策略的例子了,在扩容之后产生了新的切片,因为原数组的容量达到了最大值,再扩容都会开出一片新的内存,把原来的值拷贝过来,再进行后续操作也不会影响原数组。
总结:时刻保持cap的清醒,推荐使用第二种情况的扩容策略