I have a nil slice:
var s1 []int // len(s1) == 0, cap(s1) == 0
Which I append one element to:
s2 := append(s1, 1) // len(s2) == 1, cap(s2) == 2
Why is appending one element to a nil slice increases the capacity by 2?
Printing the slices using fmt.Printf
shows the following:
[] // s1 [1] // s2
I am also confused about why re-slicing s2[0:2]
shows a zero which was not in the original slice nor appended to it:
[1,0] // s2[0:2]
Appending to nil slice: As we know that zero value slice type is nil and the capacity and the length of such type of slice is 0. But with the help of append function, it is possible to append values to nil slice.
The slice descriptor is composed of a pair of ints, one for len and one for cap, and a pointer to the underlying data. So, what append returns is indeed a new slice and what is passed to add option is indeed a copy of the slice descriptor.
When it comes to appending a slice to another slice, we need to use the variadic function signature dots. In variadic functions in Golang, we can pass a variable number of arguments to the function and all the numbers can be accessed with the help of the argument name.
The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice. The length and capacity of a slice s can be obtained using the expressions len(s) and cap(s) . You can extend a slice's length by re-slicing it, provided it has sufficient capacity.
Go is free to provide you more capacity than you request. This improves performance by reducing the number of allocations (and possibly copying) that are required. Capacity is just the amount of space reserved before another allocation would be required.
If you append 5 elements to this slice, at least in my experiments, the capacity is 8. This shouldn't be surprising, but also shouldn't be relied on. On different platforms, or different versions of the compiler, the actual result may be different, as long as the capacity is "sufficiently large" (equal to or greater than length).
The upper index bound of a slice is defined as its capacity:
For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range. For slices, the upper index bound is the slice capacity cap(a) rather than the length. A constant index must be non-negative and representable by a value of type int; for arrays or constant strings, constant indices must also be in range. If both indices are constant, they must satisfy low <= high. If the indices are out of range at run time, a run-time panic occurs.
This is why reading past the length is not causing a panic. Even so, you shouldn't think of those zeros as part of the slice. They are indexable by the slice, but fmt.Printf(s2)
would correctly not show them because they are not part of the slice. Don't subscript this way.
In general, you want to be looking at length, not capacity. Capacity mostly is readable to assist in performance optimization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With