slice
Go定义slice
var s3 []string //不分配内存空间
if s3==nil {
fmt.Println("不分配内存空间")
}
s2 := []string{} //已经分配了内存空间
if len(s2)==0 {
fmt.Println(s2)
fmt.Println("长度为0")
}
fmt.Println(s2)
s1 := make([]int,5,10) //已经分配了内存空间
s1 = append(s1,22)
fmt.Println(s1)
不分配内存空间
[]
长度为0
[]
[0 0 0 0 0 22]
切片的本质
切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。
举个例子,现在有一个数组a := [8]int{0, 1, 2, 3, 4, 5, 6, 7},切片s1 := a[:5],相应示意图如下。
切片的扩容机制
- 首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)。
- 否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap),
- 否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
- 如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)。
切片的元素删除
a := []int{30, 31, 32, 33, 34, 35, 36, 37}
// 要删除索引为2的元素
a = append(a[:2], a[3:]...)
fmt.Println(a) //[30 31 33 34 35 36 37]
切片Tip
切片本身不存储值,只是对底层数组的引用,每个切片会指向一个底层数组,这个数组的容量够用就添加新增元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。
s1 := []int{1,2,3,4}
s2 := s1
fmt.Println(s1)
fmt.Println(s2)
s1 = append(s1,777)
fmt.Println(s1)
fmt.Println(s2)
s1[3] = 999
fmt.Println(s1)
fmt.Println(s2)
当切片扩容时,指向原来的数组就会更换
[1 2 3 4]
[1 2 3 4]
[1 2 3 4 777]
[1 2 3 4]
[1 2 3 999 777]
[1 2 3 4]
本作品采用《CC 协议》,转载必须注明作者和本文链接