golang slice
目录
slice
slice是一个数组某个部分的引用,非协程安全的。
创建
- 通过数组创建 切片的初始化格式是:var slice1 []type = arr1[start:end],start和end都是角标,含头不含尾 s:=arr[0:3] s:=arr[:3] s:=arr[0:]都是合法的
- make声明 make([]type,len,cap)cap为非必填
数据结构
type slice struct {
array unsafe.Pointer
len int
cap int
}
其中array就是指向数组的指针
从Go1.2开始slice支持了三个参数的slice,之前我们一直采用这种方式在slice或者array基础上来获取一个slice var array [10]int slice := array[2:4] 这个例子里面slice的容量是8,新版本里面可以指定这个容量 slice = array[2:4:7] 上面这个的容量就是7-2,即5。这样这个产生的新的slice就没办法访问最后的三个元素
扩容
先看几个示例:
s := make([]int, 2)
s2 := make([]int, 1)
fmt.Println(len(s), cap(s), s)
s = append(s, s2...)
fmt.Println(len(s), cap(s), s)
打印: 2 2 [0 0] 3 4 [0 0 0]
s := make([]int, 2)
s2 := make([]int, 3)
fmt.Println(len(s), cap(s), s)
s = append(s, s2...)
fmt.Println(len(s), cap(s), s)
打印: 2 2 [0 0] 5 6 [0 0 0 0 0]
s := make([]int, 1024)
s2 := make([]int, 3)
fmt.Println(len(s), cap(s))
s = append(s, s2...)
fmt.Println(len(s), cap(s))
打印: 1024 1024 1027 1280
扩容策略
If 当前长度<1024{
If 当追加后的len < 当前的2倍{
直接翻倍
}else{
新的cap=追加后的长度
}
}else{
每次扩容为当前1.25倍,循环,直到装下所有元素
}
计算出了新容量之后,还没有完,出于内存的高效利用考虑,还要进行内存对齐。通过内存对齐后才能知道最终的cap值。
slice删除
arr[low:high] For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range. For slices, the upper index bound is the slice capacity cap(a) rather than the length.
补充
- slice的最大cap是多少? 源码中slice的cap 为int类型,int和平台有关。其次cap也和能申请的内存大小有关,简单来说max = maxmemory / element.size
- slice没有缩容,必须自己注意内存泄漏
- 小心slice用的是同一个数组的坑
func main() {
s := []int{1, 2, 3, 4, 5}
s2 := append(s[0:1], 6)
fmt.Printf("%p %v %d \n", s, s, cap(s))// 0xc04200a240 [1 6 3 4 5] 5
fmt.Printf("%p %v %d", s2, s2, cap(s)) // 0xc04200a240 [1 6] 5
}