小白求助

hackerzyh · · 1950 次点击
其实`如果切片的容量小于1024个元素,那么扩容的时候slice的cap就直接翻番,乘以2;一旦元素个数超过1024个元素,cap扩容就要减缓,变成了四分之一,乘以0.25,即每次增加原来容量的四分之一`这个说法并不准确,具体扩容的大小还得看容器元素是否能`内存对齐`,例如 ```go 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切片`的底层实现,之前我已经回答过相关的问题,有兴趣看一下类似的问题 - [为什么在函数传参时,数组参数有无固定长度,会产生这样的差距,就是arr5里面的内容不会被改变,arr7却会改变,刚开始学go,求大佬赐教](https://studygolang.com/topics/12422) - [Go语言设计与实现 - 切片](https://draveness.me/golang/docs/part2-foundation/ch03-datastructure/golang-array-and-slice/) # 一、为什么 y 和 z 的结果一样 1. 创建y变量时,没有发生扩容,导致复用x的底层数组 2. 创建z变量时,同样没有发生扩容,依旧复用x的底层数组 3. 最终y和z的底层数组是一样的,即`3个变量都是用同一个底层数组`,且y和z都能访问到第4个元素,而x只能访问到第3个元素 4. 可以通过以下的例子进行验证 ```go 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多追加了一个数,导致切片的大小`len`与`cap`一样 2. 接着再对x进行追加,会导致切片发生扩容,对底层数组发生值拷贝,生成新的底层数组 3. 所以x、y和z所用的底层数组都不一样,互不影响 ```go 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](https://www.avtion.cn)
#1
x := make([]int,0, 3)
#2