Go slice 的一些知识
源码
go slice 的源码位于 go/src/runtime/slice.go 下
定义
slice 的定义如下
type slice struct { array unsafe.Pointer len int cap int }
其中包括一个指向内存实际存储空间的指针 array
slice 的长度 len
slice 的容量 cap
扩容
主要的扩容逻辑是这一段代码
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 } } }
可以看到 newcap 就是最终需要扩容的大小,cap 是我们程序所需要的容量
首先将 newcap 设置为原来容量的 2 倍
如果所需要的容量 cap 大于原来容量的 2 倍,直接把 newcap 设置为 cap
否则进入 else,将原 slice 长度与 1024 做比较,小于 1024,将 newcap 设置为原来容量的 2 倍
如果大于1024,就将容量增加原来容量大小的 1/4
这里也是直接使用了数字 1024,没有什么宏定义啊。。。也是写的很随心所欲啊
slice 使用中的一些小坑
看下面两端代码
func main() { var a [5]int = [5]int{ 1, 2, 3, 4, 5, } var b = a[0:2] b = append(b, 1, 1, 1) fmt.Println(a, b) }
打印结果 [1 2 1 1 1] [1 2 1 1 1]
func main() { var a [5]int = [5]int{ 1, 2, 3, 4, 5, } var b = a[0:2] b = append(b, 1, 1, 1, 1) fmt.Println(a, b) }
打印结果 [1 2 3 4 5] [1 2 1 1 1 1]
b 是取自于数组 a 的 slice, 我们往 b 中 append 数据
当一次数据量超过 a 的容量的时候,会给 b 重新分配一段内存, a 的数据不会变化
当一次数据量不超过 b 的容量的时候,就不会重新分配内存,a 的数据就会随着 b 而变化