小白求助

hackerzyh · 2020-10-23 17:28:34 · 2209 次点击

其实如果切片的容量小于1024个元素,那么扩容的时候slice的cap就直接翻番,乘以2;一旦元素个数超过1024个元素,cap扩容就要减缓,变成了四分之一,乘以0.25,即每次增加原来容量的四分之一这个说法并不准确,具体扩容的大小还得看容器元素是否能内存对齐,例如

func TestB(t *testing.T)  {
    a := []struct{
        b struct{}
    }{}
    a = append(a, struct{ b struct{} }{b: struct {

    }{}})
    a = append(a, struct{ b struct{} }{b: struct {

    }{}})
    a = append(a, struct{ b struct{} }{b: struct {

    }{}})
    t.Log((*reflect.SliceHeader)(unsafe.Pointer(&a)))
}

// 输出
// &{15181584 3 3}

是和int类型的切片连续追加3次容量是4有出入的

#4
更多评论

这个属于入门基础问题,涉及Slice切片的底层实现,之前我已经回答过相关的问题,有兴趣看一下类似的问题

一、为什么 y 和 z 的结果一样

  1. 创建y变量时,没有发生扩容,导致复用x的底层数组
  2. 创建z变量时,同样没有发生扩容,依旧复用x的底层数组
  3. 最终y和z的底层数组是一样的,即3个变量都是用同一个底层数组,且y和z都能访问到第4个元素,而x只能访问到第3个元素
  4. 可以通过以下的例子进行验证
func TestB(t *testing.T) {
    x := []int{}
    x = append(x, 0) // 0
    x = append(x, 1) // 0,1
    x = append(x, 2) // 0,1,2
    y := append(x, 3) // y: 0,1,2,3 x: 0,1,2
    z := append(x, 6) // z: 0,1,2,6 y: 0,1,2,6, x: 0,1,2
    _x := (*reflect.SliceHeader)(unsafe.Pointer(&x))
    _y := (*reflect.SliceHeader)(unsafe.Pointer(&y))
    _z := (*reflect.SliceHeader)(unsafe.Pointer(&z))
    t.Log(x, _x)
    t.Log(y, _y)
    t.Log(z, _z)
}

/*
=== RUN   TestB
    main_test.go:44: [0 1 2] &{824633781600 3 4}
    main_test.go:45: [0 1 2 6] &{824633781600 4 4}
    main_test.go:46: [0 1 2 6] &{824633781600 4 4}
--- PASS: TestB (0.00s)
PASS
*/

二、x多append了一个数,y和z的输出又不一样

  1. x多追加了一个数,导致切片的大小lencap一样
  2. 接着再对x进行追加,会导致切片发生扩容,对底层数组发生值拷贝,生成新的底层数组
  3. 所以x、y和z所用的底层数组都不一样,互不影响
func TestB(t *testing.T) {
    x := []int{}
    x = append(x, 0) // 0
    x = append(x, 1) // 0,1
    x = append(x, 2) // 0,1,2
    x = append(x, 3) // 0,1,2,3
    y := append(x, 6) // y: 0,1,2,3,6 x: 0,1,2,3
    z := append(x, 7) // z: 0,1,2,3,7 y: 0,1,2,3,6, x: 0,1,2,3
    _x := (*reflect.SliceHeader)(unsafe.Pointer(&x))
    _y := (*reflect.SliceHeader)(unsafe.Pointer(&y))
    _z := (*reflect.SliceHeader)(unsafe.Pointer(&z))
    t.Log(x, _x)
    t.Log(y, _y)
    t.Log(z, _z)
}

/*
=== RUN   TestB
    main_test.go:45: [0 1 2 3] &{824634321440 4 4}
    main_test.go:46: [0 1 2 3 6] &{824634425536 5 8}
    main_test.go:47: [0 1 2 3 7] &{824634425600 5 8}
--- PASS: TestB (0.00s)
PASS
*/

顺便扔个小博客

Avtion

#1

x := make([]int,0, 3)

#2