Range of slice expressions

November 23, 2023

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 satisfy low <= 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]

  1. [6 7]
  2. [8 9]
  3. A runtime panic
  4. 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. 🤷

Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .