Jake Muller
Jake Muller

Reputation: 1063

Golang sub slice

In Go, why does this code work:

package main

import (
  "fmt"
)

func main() {
  a := []int{1}
  a = a[1:]
  fmt.Println(len(a))
}

but this doesn't:

package main

import (
  "fmt"
)

func main() {
  a := []int{1}
  a = a[2:]
  fmt.Println(len(a))
}

I've heard about capacity in slices, can someone elaborate it?

Upvotes: 2

Views: 28106

Answers (2)

mfathirirhas
mfathirirhas

Reputation: 2265

Slice's capacity is always at least the same with slice's length. When unspecified, the default is always the same as length.

The definition of length of a slice is the number of element set into the slice.

The definition of capacity of a slice is the whole blocks of the slice can provide which is hidden from the caller and has default values of empty(0 for int, "" for string).

When you call value of a certain index like this a[x] then it will get the value at index x within range of lenght.

But when you re-slice the slice like this a[x:y] then it will get the slice at index x within range of capacity till y(max value must be the same with capacity). So as a caller of the slice, you can get the hidden elements of slice within the whole slice structure which default values are empty.

If you don't specify the end of re-sclicing(y) like you did above -> a[2:], then the default end of the re-slicing will be set to lenght, which make your call to a[2:] imply to a[2:1] since lenght of slice is 1. Think about it, calling a sub-slice of a[2:1], what would happen?. Exactly as the error message told us:

panic: runtime error: slice bounds out of range [2:1]

because you're calling sub-slice from the index which is not even within range of capacity(the whole structure of the slice it self). Even if 2 is within the range of slice's capacity, your call is overlapping because the starting index is larger than the capacity.

For summarize:

  • If you call sub-slice like this -> a[x:] then x must be within the range of length(inclusive)
  • If you call sub-slice like this -> a[:y] then y must be within the range of capacity(inclusive)
  • If you call sub-slice like this -> a[x:y] then x and y must be within the range of capacity(inclusive) and x<=y.

Upvotes: 2

torek
torek

Reputation: 489828

The Go specification contains the answer to both of your questions:

Slice expressions

Slice expressions construct a substring or slice from a string, array, pointer to array, or slice. There are two variants: a simple form that specifies a low and high bound, and a full form that also specifies a bound on the capacity.

Simple slice expressions

[snippage]

For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range.

Since len(a) is 1, the index 1 is in range, but the index 2 is out of range.

Full slice expressions

For an array, pointer to array, or slice a (but not a string), the primary expression

a[low : high : max]

constructs a slice of the same type, and with the same length and elements as the simple slice expression a[low : high]. Additionally, it controls the resulting slice's capacity by setting it to max - low. Only the first index may be omitted; it defaults to 0. ...

Read the entire spec. It can be a bit slow going, but it's not all that long. There's no need to memorize it all, but having gone through the whole thing once, you should be able to remember that you read that somewhere, and then go back and find what you are looking for.

Upvotes: 10

Related Questions