Reputation: 20628
My code:
package main
import (
"fmt"
)
func main() {
a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
b := a[1:4]
fmt.Println("a:", a)
fmt.Println("b:", b)
// Works fine even though c is indexing past the end of b.
c := b[4:7]
fmt.Println("c:", c)
// This fails with panic: runtime error: index out of range [4] with length 3
// d := b[4]
}
Output:
a: [0 1 2 3 4 5 6 7 8 9]
b: [1 2 3]
c: [5 6 7]
If I uncomment the line that contains d := b[4]
, it leads to this this error:
panic: runtime error: index out of range [4] with length 3
My question:
Why is it okay to access b[4:7]
even though the index 4 is out of range for b
which has a length 3 but it is not okay to access b[4]
? What Go language rules explain this behavior?
Upvotes: 4
Views: 849
Reputation: 417612
Relevant rules: Spec: Index expressions and Spec: Slice expressions.
In short: when indexing, index must be less than the length. When slicing, upper index must be less than or equal to the capacity.
When indexing: a[x]
the index
x
is in range if0 <= x < len(a)
, otherwise it is out of range
When slicing: a[low: high]
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 capacitycap(a)
rather than the length.
When you do this:
b := a[1:4]
b
will be a slice sharing the backing array with a
, b
's length will be 3
and its capacity will be 9
. So later it is perfectly valid to slice b
even beyond its length, up to its capacity which is 9
. But when indexing, you can always index only the part covered by the slice's length.
We use indexing to access current elements of a slice or array, and we use slicing if we want to create a fragment of an array or slice, or if we want to extend it. Extending it means we want a bigger portion (but what is still covered by the backing array).
Upvotes: 8