去切片长度为容量-1,为什么?

Consider the go code below:

fruits := [4]string{"apple", "orange", "mango"}
tasty_fruits := fruits[1:3]
fmt.Println(len(tasty_fruits))
fmt.Println(cap(tasty_fruits))
fmt.Println(tasty_fruits)

Ouputs:

2
3
[orange mango]

What I don't understand is why is the capacity of tasty_fruits 3, intuitively I would expect it to be 2 since that is the length of the slice?

And if the capacity of tasty_fruits is 3 why does:

tasty_fruits[2] = "nectarine"

result in:

panic: runtime error: index out of range

This line:

fruits := [4]string{"apple", "orange", "mango"}

Creates an array, not a slice. It has 4 elements even though you only supplied 3. Output of fmt.Printf("%q", fruits):

["apple" "orange" "mango" ""]

Slicing it:

tasty_fruits := fruits[1:3]

Results in:

["orange" "mango"]

Length: obviously 2. Capacity?

The capacity is ... the sum of the length of the slice and the length of the [underlying] array beyond the slice.

Since there is one element after "mango" in the underlying array, capacity is 2 + 1 = 3.

Indexing the slice (tasty_fruits): spec: Index expressions:

For a of slice type S: a[x]

  • if x is out of range at run time, a run-time panic occurs

x is in range if 0 <= x < len(a), otherwise it is out of range. Since len(tasty_fruits) is 2, the index 2 is out of range, and therefore runtime panic occurs.

You can't index the slice beyond the length of the slice, even if capacity would allow it. You can only reach the elements beyond the length if you reslice the slice, e.g.:

tasty_fruits2 := tasty_fruits[:3]
tasty_fruits2[2] = "nectarine" // This is ok, len(tasty_fruits2) = 3
fmt.Printf("%q", tasty_fruits2)

Output:

["orange" "mango" "nectarine"]

You are creating a slice with the capacity of 3 (because [1:3] could contain 3 elements: 1,2 and 3). But as the slice you are copying from does not contain an element on 3, only 1 and 2 are copied.

The capacity of a slice depends on the size of the underlying array. So if you change fruits to have a difference size, for example:

fruits := [5]string{"apple", "orange", "mango"}

cap(tasty_fruits) will return 4 instead of 3.

So capacity means the maximum size of the slice can be extended to. "A slice cannot be grown beyond its capacity. Attempting to do so will cause a runtime panic".

And slices are essentially c pointers with boundary check. The length of a slices, is the boundary it will check during run time. As a result, if you try to access anything beyond length, a runtime panic will also be caused.

And yes length <= capacity is always true.

For more details please read Go Slices: usage and internals

As documented here: http://blog.golang.org/slices "The Capacity field records how much space the underlying array actually has; it is the maximum value the Length can reach. Trying to grow the slice beyond its capacity will step beyond the limits of the array and will trigger a panic."