What is the appropriate way to clear a slice in Go?
Here's what I've found in the go forums:
// test.go
package main
import (
"fmt"
)
func main() {
letters := []string{"a", "b", "c", "d"}
fmt.Println(cap(letters))
fmt.Println(len(letters))
// clear the slice
letters = letters[:0]
fmt.Println(cap(letters))
fmt.Println(len(letters))
}
Is this correct?
To clarify, the buffer is cleared so it can be reused.
An example is Buffer.Truncate function in the bytes package.
Notice that Reset just calls Truncate(0). So it appears that in this case line 70 would evaluate: b.buf = b.buf[0 : 0]
http://golang.org/src/pkg/bytes/buffer.go
// Truncate discards all but the first n unread bytes from the buffer.
60 // It panics if n is negative or greater than the length of the buffer.
61 func (b *Buffer) Truncate(n int) {
62 b.lastRead = opInvalid
63 switch {
64 case n < 0 || n > b.Len():
65 panic("bytes.Buffer: truncation out of range")
66 case n == 0:
67 // Reuse buffer space.
68 b.off = 0
69 }
70 b.buf = b.buf[0 : b.off+n]
71 }
72
73 // Reset resets the buffer so it has no content.
74 // b.Reset() is the same as b.Truncate(0).
75 func (b *Buffer) Reset() { b.Truncate(0) }
It all depends on what is your definition of 'clear'. One of the valid ones certainly is:
But there's a catch. If slice elements are of type T:
then enforcing
len(slice)
to be zero, by the above "trick", doesn't make any element ofeligible for garbage collection. This might be the optimal approach in some scenarios. But it might also be a cause of "memory leaks" - memory not used, but potentially reachable (after re-slicing of 'slice') and thus not garbage "collectable".
I was looking into this issue a bit for my own purposes; I had a slice of structs (including some pointers) and I wanted to make sure I got it right; ended up on this thread, and wanted to share my results.
To practice, I did a little go playground: https://play.golang.org/p/9i4gPx3lnY
which evals to this:
Running that code as-is will show the same memory address for both "meow" and "meow2" variables as being the same:
which I think confirms that the struct is garbage collected. Oddly enough, uncommenting the commented print line, will yield different memory addresses for the meows:
I think this may be due to the print being deferred in some way (?), but interesting illustration of some memory mgmt behavior, and one more vote for:
Setting the slice to
nil
is the best way to clear a slice.nil
slices in go are perfectly well behaved and setting the slice tonil
will release the underlying memory to the garbage collector.See playground
Prints
Note that slices can easily be aliased so that two slices point to the same underlying memory. The setting to
nil
will remove that aliasing.This method changes the capacity to zero though.