35

My question is about slice length and capacity. I'm learning about Go here: https://tour.golang.org/moretypes/11.

(My question was marked as a possible duplicate of this; however, this is not the case. My question is specifically about the cutting off the first few elements of a slice and the implications of that.)

Why does the line s = s[2:] decrease the capacity when s = s[:4] and s = s[:0] do not? The only difference I see is that there is a number before the colon in s = s[2:] while there is a number after the colon in the other two lines.

Is there any way to recover the first two elements that we cut off with s = s[2:]?

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    s = s[:0]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)
}

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

After clicking the Run button, we get the following.

len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Pizzas
  • 419
  • 4
  • 6
  • Possible duplicate of [Go slices - capacity/length?](http://stackoverflow.com/questions/36683911/go-slices-capacity-length) (answer: "the capacity will be the first element till the last of the backing array") – kennytm Apr 08 '17 at 14:06
  • Possible duplicate of [Does Go have no real way to shrink a slice? Is that an issue?](http://stackoverflow.com/questions/16748330/does-go-have-no-real-way-to-shrink-a-slice-is-that-an-issue) – Jonathan Hall Apr 08 '17 at 15:02
  • other new comers can read this answer https://stackoverflow.com/a/62638755/4693568. – Ja8zyjits Jun 29 '20 at 13:05
  • Can someone please explain how we are able to print `[2,3,5,7]` coming from `s[:0]` to `s[:4]`. But when we are coming from `s[:4]` to `s[2:]` go seemed to forget about last two elements `11,13` and printed only `[5,7]` even though it has sufficient capacity. I went through [this](https://go.dev/blog/slices-intro) link and still couldn't find the answer. – MonkeyDLuffy Sep 04 '21 at 07:21

3 Answers3

31

You can read more about slices here. But I think this passage answers your question:

Slicing does not copy the slice's data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices. Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice.

So you cannot recover the slice data if you are assigning it to the same variable.

The capacity decrease is because by dropping the first 2 elements you are changing the pointer to the new slice (slices are referenced by the pointer to the first element).

How slices are represented in the memory: def

make([]byte, 5)

memory vis

s = s[2:4]

slice cap decrease

Alex Efimov
  • 3,335
  • 1
  • 24
  • 29
  • 2
    Thank you, Alex. The link was very helpful. I didn't quite follow the diagram that you posted here until I reviewed the diagram above it in the link. (I didn't understand that the blue, purple, and pink squares represented the internals of a slice.) – Pizzas Apr 08 '17 at 14:32
  • I have updated the answer to make more understandable. – Alex Efimov Apr 08 '17 at 14:40
  • 14
    When I was reading the golang tutorial I asked myself the same question. Alex answers perfectly here, and I believe it's a mistake of the tutorial authors not to explain why this behaviour. – carnicer May 21 '18 at 09:52
  • In my opinion, this answer could be more comprehensive with 'end'-slicing (e.g. `s[:4]`) explained verbally as well. What I understood looking at the images is that 'start'-slicing changes the pointer AND decreases `len` and `cap` by the same value, while 'end'-slicing just decreases `len`. – Maks Babarowski Nov 17 '21 at 12:15
1

You can use a full slice expression:

package main

func main() {
   s := []int{2, 3, 5, 7, 11, 13}
   { // example 1
      t := s[:0]
      println(cap(t) == 6)
   }
   { // example 2
      t := s[:0:0]
      println(cap(t) == 0)
   }
}

https://golang.org/ref/spec#Slice_expressions

Zombo
  • 1
  • 62
  • 391
  • 407
0

The slices.Clip of "golang.org/x/exp/slices" could reduce the capacity of slice through Full slice expressions.

Clip removes unused capacity from the slice, returning s[:len(s):len(s)].

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    s = s[:4]
    printSlice(s)

    s = slices.Clip(s)
    printSlice(s)

}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
len=6 cap=6 [2 3 5 7 11 13]
len=4 cap=6 [2 3 5 7]
len=4 cap=4 [2 3 5 7]

Playground

zangw
  • 43,869
  • 19
  • 177
  • 214