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],相应示意图如下。

slice

切片的扩容机制

  • 首先判断,如果新申请容量(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 协议》,转载必须注明作者和本文链接
打不死的小强
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!