日常开发中slice经常用,就是对于一个老司机来说有时也容易忽略。一起看下:

//Slice 数据结构
type Slice struct {
ptr unsafe.Pointer // Array pointer
len int // slice length
cap int // slice capacity
}
//使用make创建
make([]T, length, capacity)
len()取数组长度,在内存中进行了初始化实际存在的元素的个数
cap()取数组容量,最大可存放元素个数(每次cap改变的时候指向array内存的指针都在变化)
注意:slice的容量,如果通过make函数创建slice的时候指定了容量参数,那内存管理器会根据指定的容量的值先划分一块儿内存空间,然后才在其中按长度,存放数组元素,多余的部分处于空闲状态。
在slice上追加元素的时候,首先会到这块儿空闲的内存中,如果添加的元素的个数超过了容量的值,内存管理器会重新划分一块容量值为原容量2倍大小的内存空间,这个机制可以提升运算性能,因为内存的频繁重新划分会降低性能。
实际go在append的时候放大cap是有规律的。在 cap 小于1024的情况下是每次扩大到 2 * cap ,当大于1024之后就每次扩大到 1.25 * cap 。
在实际使用中,我们最好事先预期好一个cap,这样在使用append的时候可以避免反复重新分配内存复制之前的数据,减少不必要的性能消耗。
示例:
package main
import “fmt”
func main() {
/* 创建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)
/* 打印原始切片 */
fmt.Println(“numbers ==”, numbers)
/* 打印子切片从 索引 1(包含) 到索引4(不包含)*/
fmt.Println(“numbers[1:4] ==”, numbers[1:4])
/* 默认下限为 0*/
fmt.Println(“numbers[:3] ==”, numbers[:3])
/* 默认上限为 len(s)*/
fmt.Println(“numbers[4:] ==”, numbers[4:])
numbers1 := make([]int,0,5)
printSlice(numbers1)
/* 打印子切片从索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
printSlice(number2)
/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
number3 := numbers[4:5]
printSlice(number3)
number3 = append(number3, 4,5,6,7,8)
printSlice(number3)
}
func printSlice(x []int){
fmt.Printf(“len=%d cap=%d slice=%v\n”,len(x),cap(x),x)
}
执行以上代码输出结果为:
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=3 cap=5 slice=[4] //此时指针已经到index 2 处,所以cap容量为9-2=7
len=6 cap=10 slice=[5 6 4 5 6 7 8] //此时cap已经扩容为2倍
更多内容请关注每日编程,每天进步一点。