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.png

Go 1.18 又有不同

ref

https://www.bookstack.cn/read/GoExpertProgramming/chapter01-1.2-slice.md

上一篇下一篇

猜你喜欢

热点阅读