Let's play a little game
You've got this innocent looking Go program:
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice("init", s)
s = s[:0] // looks like a reassignment, right?
printSlice("s[:0]", s)
s = s[:4]
printSlice("s[:4]", s)
s = s[2:]
printSlice("s[2:]", s)
}
func printSlice(name string, s []int) {
fmt.Printf("%-6s len=%d cap=%d %v\n", name, len(s), cap(s), s)
}
Run it, and you get:
init len=6 cap=6 [2 3 5 7 11 13]
s[:0] len=0 cap=6 []
s[:4] len=4 cap=6 [2 3 5 7]
s[2:] len=2 cap=4 [5 7]
Hold up.. We made the slice zero-length, right? Shouldn't the values disappear? Well, not exactly..
What actually happened
Let's talk about what a slice really is.
Under the hood, a slice isn't your data. It's a tiny 3-field struct that points to your data:
type slice struct {
Data *T
Len int
Cap int
}
It's basically a view into an array
So when you do:
s := []int{2, 3, 5, 7, 11, 13}
Memory looks like this:
Backing array: [2 3 5 7 11 13]
Slice view: [2 3 5 7 11 13] (len=6, cap=6)
Let's take each operation we did in our main code snippet one by one
s = s[:0]
You're not deleting anything. You're just saying: "Hey, I don't want to look at any of those elements right now"
now your slice has len=0, but it still points to the same underlying array
Backing array: [2 3 5 7 11 13]
Slice view: [] (len=0, cap=6)
Same goes for the next operation
s = s[:4]
The data comes back:
Backing array: [2 3 5 7 11 13]
Slice view: [2 3 5 7] (len=3, cap=6)
We didn't recreate anything, we just widened the slice window again.
So if you think s = s[:0] means "clear the slice", it doesn't. If you want to actually wipe the data, you need to overwrite it:
for i := range s {
s[i] = 0
}
s = s[:0]
or if you're looking for a new allocation:
s = []int{}
Example
a := []int{1, 2, 3, 4}
b := a[:2]
c := a[1:]
b[1] = 99
fmt.Println(a) // [1 99 3 4]
fmt.Println(c) // [99 3 4]
And that's because they're literally sharing the same memory!