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
                }
            }
        }
    ...........
}
  1. 如果预估新的容量大于容量的2倍,直接使用新容量;
  2. 不满足情况1,老的容量小于1024,则新的容量直接等于就容量的2倍;
  3. 不满足情况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
  
}
posted @ 2022-05-27 16:30  凌易说-lingyisay  阅读(42)  评论(0编辑  收藏  举报