1. slice的结构
type slice struct {
index *interface //指向首元素的指针
len int //长度
cap int //容量
}
slice是值类型
slice类型声明后类似于:
var arr slice
而非 var arr *slice
append时,如果超过cap容量,会重新分配空间.
新空间的指针会被保存在index中,slice本身的指针不变.
举个栗子🌰:
func F() {
intArr := make([]int, 1)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
defer f(intArr)
intArr = append(intArr, 1)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
return
}
func f(intArr []int) {
fmt.Println(&intArr[0], len(intArr), cap(intArr))
}
//结果
0xc42000d2d0 1 1
0xc42000d300 2 2
0xc42000d2d0 1 1
- 在defer中,保存了一个副本,拷贝了intArr的值,
在后面append中,因为容量(cap)不够,给intArr的index重新分配了空间,
因为defer中保存的是intArr的值,所以defer打印出来的是原来的slice值
func F1() {
intArr := make([]int, 1)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
defer f1(&intArr)
intArr = append(intArr, 1)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
return
}
func f1(ia *[]int) {
intArr := *ia
fmt.Println(&intArr[0], len(intArr), cap(intArr))
}
//结果
0xc42000d2d0 1 1
0xc42000d300 2 2
0xc42000d300 2 2
- 在defer中,保存了一个副本,拷贝了intArr的指针,
在后面append中,因为容量(cap)不够,给intArr的index重新分配了空间,
因为defer中保存的是intArr的指针,所以打印出来的是新的的slice值
2. slice的扩容
func F() {
intArr := make([]int, 0, 0)
intArr = append(intArr, 1)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
intArr = append(intArr, 2)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
intArr = append(intArr, 3)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
intArr = append(intArr, 4)
fmt.Println(&intArr[0], len(intArr), cap(intArr))
return
}
//结果
0xc42000d2d0 1 1
0xc42000d300 2 2
0xc4200cc660 3 4
0xc4200cc660 4 4
在对slice进行append等操作时,可能会造成slice的自动扩容。其扩容时的大小增长规则是:
- 如果新的大小是当前大小2倍以上,则大小增长为新大小
- 否则循环以下操作:如果当前大小小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新大小。