ataraskov.dev

About everything and nothing


Go slice gotchas

Gotcha - a valid construct in a system, program or programming language that works as documented but is counter-intuitive and almost invites mistakes because it is both easy to invoke and unexpected or unreasonable in its outcome [wikipedia].

Slice is actually a struct (holding info about pointer to the underlaying array, it’s lenght, and capacity), but it behaves like a pointer. Because it is just a “view” of some memory area.

Sub-slice modification can cause modification of the original slice:

1
2
3
4
5
	a := []int{1, 2}
	b := a[:1]
	b[0] = 9            /* what can go wrong? */
	fmt.Println("a", a) /* [9 2] */
	fmt.Println("b", b) /* [9] */

 

1
2
3
4
5
	a := []int{1, 2}
	b := a[:1]
	b = append(b, 9)    /* what can go wrong? */
	fmt.Println("a", a) /* [1 9] */
	fmt.Println("b", b) /* [1 9] */

 

What about append to create a new slice? Nope that’s a bad idea:

1
2
3
4
5
6
7
	a := make([]int, 2)
	a = append(a, 1)
	b := append(a, 2)
	c := append(a, 9)   /* what can go wrong? */
	fmt.Println("a", a) /* [0 0 1]            */
	fmt.Println("b", b) /* [0 0 1 9] <- oops  */
	fmt.Println("c", c) /* [0 0 1 9]          */

 

We can see common pattern here. Even in a modern and memory-safe language there are options to mess with memory and pointers.

There is a good example of another gotcha with slices, realated to garbage collector. Check it out here. In short, when you create a slice, in many cases it would be benificial and safer to create it as a copy:

1
2
3
    src := []int{1,2}
    dst := make([]int, len(src))
    copy(dst, src)

 

Just don’t overdo copying, as memory is not infinite unfortunately ;)

References:

Thu Jun 29, 2023 / 308 words / Golang Programming Gotchas