引子
刚刚写了一个API用到了Golang的Slice,想着用Slice这么久了竟然不知道这到底是个什么东西。
只知道Slice和常规数组相比是可自动变长的,内部到底是怎么实现的呢?
于是今天就和同事一起研究了一下Golang中Slice的自动扩容机制,这里采用的是Golang1.12版本。
闲话少说,直接开整:
例1:
package main
import (
"fmt"
)
func main() {
//定义一个无初始长度的切片
a := []string{}
for i := 0; i < 6; i++{
a = append(a, "aaa")
fmt.Println("====")
//Slice的容量
fmt.Println(cap(a))
//Slice的长度
fmt.Println(len(a))
fmt.Println("====")
}
}
输出结果:
1
1
--------
2
2
--------
4
3
--------
4
4
--------
8
5
--------
8
6
--------
结论
由输出结果可以看出,容量达到2之后,当长度大于2时,Slice的容量会自动扩容为原来的2倍。
这里可以得出,Slice的容量会自动扩容的起点是2。
例2:
package main
import (
"fmt"
)
func main() {
//定义一个有初始长度的切片,这里为长度为5
a := make([]string, 5)
for i := 0; i < 10; i++{
a = append(a, "aaa")
//Slice的容量
fmt.Println(cap(a))
//Slice的长度
fmt.Println(len(a))
fmt.Println("--------")
}
}
输出结果:
10
6
--------
10
7
--------
10
8
--------
10
9
--------
10
10
--------
20
11
--------
20
12
--------
20
13
--------
20
14
--------
20
15
--------
结论
看出来例2与例1的区别了吧,当定义一个有初始长度的切片时,切片的容量为初始长度的2倍。
知识点
1.当切片的容量超过2048之后再次扩容每次只会扩容512个,但不是固定的,具体可以看下源码,这里我是使用的Goland,对应包的路径为:
/usr/local/Cellar/go/1.12/libexec/src/runtime/slice.go 方法名:growslice()
2.每一次扩容都会重新开辟一块内存空间,这块内存空间是原来内存空间的2倍,然后将老的数据复制到新开辟的内存空间中,然后释放
老的内存空间。