go slice切片
go slice 切片
https://juejin.cn/post/6979108608122290212
结构体
type slice struct {
array unsafe.Pointer//指针
len int // 长度
cap int // 容量
}
定义的三种方式
1、var 切片名 []type
var s []int
2、使用make()函数定义,make([]type,len)
var s []int = make([]int,1) //len=1 cap=1
3、指定容量make([]type, len, cap),len初始化长度,cap为可变参数
var s []int = make([]int,3,4) //s [0 0 0]
容量
容量的用途是append扩容时,如果新的长度小于容量,不会更换底层数组,内存地址不变;否则,go会重新申请一个底层数组,拷贝这边的值过去,把原来的数组丢掉,内存地址改变(已经是一个新的数组)。
扩容
func growslice(et *_type, old slice, cap int) slice {
...........
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
...........
}
- 如果预估新的容量大于容量的2倍,直接使用新容量;
- 不满足情况1,老的容量小于1024,则新的容量直接等于就容量的2倍;
- 不满足情况2,就容量大于等于1024,则旧容量小于需要的容量,则就容量不停的*1.25,直到大于新容量。
func TestSlice(t *testing.T) {
s := make([]int,1024,1024)
// 旧容量1024
fmt.Println(cap(s)) // 1024
s = append(s,1)
// 扩容完 1024 * 1.25 = 1280
fmt.Println(cap(s)) // 1280
add := make([]int,255)
s = append(s,add...)
// 再添加255个元素正好达到1280,容量不变
fmt.Println(cap(s)) // 1280
// 神奇的事情发生了,再次扩容应该为1280 * 1.25 = 1600,但实际为1696
s = append(s,1)
fmt.Println(cap(s)) // 1696
}