Go 中重新构造切片是一个常数时间操作吗?

The*_*ist 3 memory go time-complexity slice

我在 Go 中有一个坐标对 ( ) 的 FIFO 队列[x, y]

type Copair [2]int
type Queue []Copair
var q = Queue{ ... preloaded values ... }
Run Code Online (Sandbox Code Playgroud)

API 定义如下,其中重要的部分是函数pop()

func (q Queue) push(p Copair) {
    q = append(q, p)
}

func (q Queue) pop() (error, Copair) {
    if q != nil && len(q) >= 1 {
        q = q[1:]
        return nil, q[0]
    } else {
        return errors.New("index out of range [0]"), nil
    }
}
Run Code Online (Sandbox Code Playgroud)

因为q = q[1:]我正在重新构造切片,理论上它只需要在内存中更改一个地址,因此是一项恒定时间操作。现在理所当然,我们正在逐渐丢失堆上的字节(或者谁知道,Go 的逃逸分析可能足够聪明,可以将其放在堆栈上),我希望垃圾收集器可以回收这些字节以避免内存泄漏,最终我们将到达堆边界,运行时将不得不将整个队列复制到其他地方,这肯定是一个线性时间操作。但...

切片重构是通过q = q[1:]恒定时间操作进行的,还是与队列的大小成线性关系?如果(正如我怀疑的那样)答案是“这取决于”,那么它取决于什么条件,以及是否有任何简单的经验法则可以解决这个问题?

Bur*_*dar 7

切片是一个恒定时间操作。切片头包含指向底层数组的指针、大小和容量。该操作q:=q[1:]只是创建一个新的标头,并调整数组指针、大小和容量。