17
package main

import "fmt"

func main() {
    a := make([]int, 5)
    printSlice("a", a)
    b := make([]int, 0, 5)
    printSlice("b", b)
    c := b[1:]
    printSlice("c", c)
}


func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

The above gives me an out of bounds error:

a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
panic: runtime error: slice bounds out of range

goroutine 1 [running]:
main.main()
   /private/var/folders/q_/53gv6r4s0y5f50v9p26qhs3h00911v/T/compile117.go:10 +0x150

Why is the slicing expression to create the c slice results in an error?

icza
  • 389,944
  • 63
  • 907
  • 827
Loki
  • 307
  • 1
  • 2
  • 7

1 Answers1

22

In short: The problem is not with the lower bound which can be equal to or greater than len() (the upper limit is dictated by cap() in case of slices). The problem is with the higher bound: it must be greater than or equal to the lower bound. And since you didn't specify the higher bound, it defaults to len() (and not to cap()!) which is 0. And 1 is not less than or equal to 0.

Spec: Slice expressions:

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.

Since you are slicing a slice, indices are in range if:

0 <= low <= high <= cap(a)

So this line:

c := b[1:]

Is invalid, because:

A missing low index defaults to zero; a missing high index defaults to the length of the sliced operand.

So in your case low = 1 and high = 0 (implicit), which does not satisfy:

0 <= low <= high <= cap(a)

So for example the following expressions are valid:

c := b[1:1]        // c len=0 cap=4 []
c := b[1:2]        // c len=1 cap=4 [0]
c := b[1:cap(b)]   // c len=4 cap=4 [0 0 0 0]
blackgreen
  • 34,072
  • 23
  • 111
  • 129
icza
  • 389,944
  • 63
  • 907
  • 827
  • the problem gets trickier because if you use non-literal expressions (see https://go.dev/play/p/Yv5EX1QNRD-) then the compiler won't give a warning about lower > higher. At runtime this lack of compliance about slicing gets translated into a panic. Implicitly the expression `b[1:]` uses a non-literal expression (`len(b)` as icza highlight) for the higher bound and that, at the end, causes the panic. Just to add. – Victor Dec 13 '21 at 17:22