目录

golang slice

slice

slice是一个数组某个部分的引用,非协程安全的。

创建

  1. 通过数组创建 切片的初始化格式是:var slice1 []type = arr1[start:end],start和end都是角标,含头不含尾 s:=arr[0:3] s:=arr[:3] s:=arr[0:]都是合法的

./1535364623175.png

  1. make声明 make([]type,len,cap)cap为非必填

./1535367197831.png

数据结构

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

其中array就是指向数组的指针

./1535423383975.png

从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.

补充

  1. slice的最大cap是多少? 源码中slice的cap 为int类型,int和平台有关。其次cap也和能申请的内存大小有关,简单来说max = maxmemory / element.size
  2. slice没有缩容,必须自己注意内存泄漏
  3. 小心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
}