go不同版本slice append后竟然执行结果不一样
2023-02-16 本文已影响0人
robertzhai
package main
import (
"fmt"
)
func AddElement(slice []int, e int) []int {
return append(slice, e)
}
func main() {
var slice []int
slice = append(slice, 1, 2, 3)
fmt.Println("before AddElement cap slice:", cap(slice))
newSlice := AddElement(slice, 4)
fmt.Println("after AddElement cap newSlice :", cap(newSlice))
fmt.Println(&slice[0] == &newSlice[0])
}
版本差异
go1.13.15 darwin/amd64 执行返回 true
before AddElement cap slice: 4
after AddElement cap newSlice : 4
true
go 1.17 执行返回 false
before AddElement cap slice: 3
after AddElement cap newSlice : 6
false
结论
slice 动态数组扩容算法不同的版本略有差异
一次添加多个元素时,本例是3个, go 13 是一个一个添加,扩容(0->1->2->4),go17 是一次加3个(0->3->6),整体还是 <1024 每次2倍,>=1024 每次 1.25倍
使用append()向切片追加元素时有可能触发扩容,扩容后将会生成新的切片
image.png
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.cap < 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
}
}
}
扩容示例
image.pngGo 1.18 又有不同
ref
https://www.bookstack.cn/read/GoExpertProgramming/chapter01-1.2-slice.md