yongjieyongjie
yongjieyongjie

Reputation: 893

Resizing of slices - whether to check for `len(slice) > 1` or `newCap > 2*len(slice)`

In the Go Programming Language book, the author gave the following code example of an append() function that accepts as arguments a []int and an int, and will handle resize accordingly:

// gopl.io/ch4/append
func appendInt(x []int, y int) []int {
    var z []int
    zlen := len(x) + 1
    if zlen <= cap(x) {
        // There is room to grow. Extend the slice.
        z = x[:zlen]
    } else {
        // There is insufficient space. Allocate a new array.
        // Grow by doubling, for amortized linear complexity.
        zcap := zlen
        if zcap < 2*len(x) { // Question: Why not len(x) > 1?
            zcap = 2 * len(x)
        }
        z = make([]int, zlen, zcap)
        copy(z, x)
    }
    z[len(x)] = y
    return z 
}

Question

Why is the innermost check written as if zcap < 2*len(x) instead of the equivalent if len(x) > 1?

The latter appears clearer to me and signals the intention that if the initial slice has length of 0 or 1, we do not allocate additional capacity after appending the new element.

Details on Equivalence of zcap < 2*len(x) and len(x) > 1

We can see that the value of zcap is assigned from zlen, which in turn has the value len(x) + 1, so if we arrange the inequality:

zcap < 2*len(x)

after substituting zcap := zlen, we get:

zlen < 2*len(x)

after substituting zlen := len(x) + 1, we get:

len(x) + 1 < 2*len(x)

after rearranging, we get:

len(x) > 1

Upvotes: 0

Views: 65

Answers (1)

hyz
hyz

Reputation: 492

You are right, zcap < 2*len(x) is equivalent to len(x) > 1. You could totally replace zcap < 2*len(x) with len(x) > 1 in this function.

But according to the source code, There is another function named appendslice. In this function, you couldn't do a replacement.

I think author use zcap < 2*len(x) only for keeping two function consistent. The main purpose here is to avoid frequent allocation.

Upvotes: 1

Related Questions