1

I am reading A Tour of Go and get confused about a slicing case

s = s[:0]

After this operation, the len() of s becomes 0 but the cap() does not. Why is the capacity not decreased? When would one want to use this 'feature'?

nos
  • 19,875
  • 27
  • 98
  • 134
  • 2
    let's say you use that slice as a stack that grows and shrinks. you've popped the last element from the stack, it's len is 0. now you push some items to it. performance would be disastrous if we'd need to start allocating and growing the capacity again in that case. – Not_a_Golfer Nov 04 '16 at 20:49
  • 2
    Here's a use of `[:0]`: [Write to beginning of the buffer in Golang?](http://stackoverflow.com/a/40234309/1705598) Also related: [Concatenate two slices in Go](http://stackoverflow.com/a/40036950/1705598) – icza Nov 04 '16 at 21:20
  • 1
    Great question! The following blog post is also worth reading: https://blog.golang.org/go-slices-usage-and-internals – Sam Whited Nov 05 '16 at 14:47

2 Answers2

6

You can actually use the three-index slicing to get the zero-capped slice:

s = s[:0:0]

Playground: https://play.golang.org/p/YetCdJVWrB.

Ainar-G
  • 34,563
  • 13
  • 93
  • 119
2

The choice to not modify the capacity is likely a performance optimization. Slices are basically 'dynamic arrays', they intend to provide the abstraction that the array's capacity is unlimited. In reality, capacity is of course limited by system memory, however if a slice is at capacity and you append an item to it, Go will allocate new memory for the array to provide that capacity (assuming it's available, if it's not your app will ofc panic).

The length represents the actual indexable item count in the slice, while the capacity tells you how much underlying memory is there. When you do those reslicing operations, there is no immediate need to free the memory and therefor it remains allocated, that is why the slices capacity remains unchanged but the length goes to zero.

Overall, this likely leads to better application performance since the memory is still available should subsequent statements append items to the slice. In practice you generally don't need to worry about capacity. I would recommend keeping it in the back of your mind however.

The times where it's most relevant, imo, is when you're reading data from some source and you know the size of that data, or at least have a rough idea, and you're putting that into a slice. In such a circumstance your application will perform better if you initialize the slice with an appropriate capacity. If you provide no length or capacity arguments (capacity defaults to length if only length is provided) then you may find the default slice growth is fairly inefficient, or at the very least, is introducing inefficiency that can quite easily be avoided.

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115