Simple slice expressions
…
For arrays or strings, the indices are in range if
0 <= low <= high <= len(a)
, otherwise they are out of range.
This is probably intuitive.
a := [5]int{1, 2, 3, 4, 5}
s := "Abracadabra"
a[-1] // Out of range
s[5:1] // Out of range
a[12] // Out of range
s[999] // Out of range
For slices, the upper index bound is the slice capacity
cap(a)
rather than the length.
Now this one is not nearly so intuitive. Or useful, IMO… but it means that this code is valid:
a := [5]int{1, 2, 3, 4, 5}
s := a[:1] // len(s) == 1, s == []int{1}
s2 := s[:3] // len(s2) == 3, s2 == []int{1, 2, 3}
s3 := s[2:3] // len(s3) == 1, s3 == []int{3}
In other words, it’s possible to take a slice of a slice, and get a result that isn’t even in the original slice at all. 🤯
And this is the explanation for yesterday’s quiz. Full recap and answer below.
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 satisfylow <= high
.
Why do these rules only apply to constants? Well, they only apply to constants at compilation time. For variables, they still apply, but at run-time, which results in a different error condition:
If the indices are out of range at run time, a run-time panic occurs.
Quotes from The Go Programming Language Specification Version of August 2, 2023
Recap of yesterday’s quiz question:
Consider the following program. What is its output?
package main import "fmt" func main() { a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} s := a[2:5] s2 := s[5:7] fmt.Println(s2) }
[6 7]
[8 9]
- A runtime panic
- A compilation error
And as was explained above, the index upper bound for a slice expression of a slice, is the slice’s capacity, not its length. That capacity corresponds to the length of the backing array. So in the case of s2 := s[...]
, the range for valid indexes is 0..8
, even though len(s)
is only 2
.
This means the expression s2 := s[5:7]
refers to [8 9]
, since its ultimately referencing the backing array (a
), not s
.
Confusing, eh? I trust there’s a reason this functionality is in the spec. I’ve never needed it. 🤷