Slices in Golang: Common Mistakes and Best Practices
In this story we want to discuss about slices in Golang and see some different scenarios to avoid common mistakes. Let’s dive in!
A slice in Golang is a dynamically size data structure that is a reference to an underlying array. We must consider passing a slice to a function that modifies it will affect the original slice outside the function.
Since we already know the fundamental of slices in Golang, we will skip the part of introducing len
, cap
and other basic concepts about slices.
1. nil slices VS empty slices
Although nil slices and empty slices have the same behavior, it is important to know a nil
slice has no underlying array while an empty slice referencing an underlying array with zero length.
Be aware appending to a nil
or zero-length slice needs allocation even though appending to a non-nil slice with enough capacity doesn’t need allocation. So, in most situations having a non-zero capacity (with well predicted value) is advantageous.
2. make another slice form original one
Let’s imagine, we want to pop an item from an original slice to a new one, as below example: (we want to modify s2
that only contains 22,44,88
)
As we saw in the above code this result could be dangerous to our program so the correct way of doing this kind of operation could be:
3. copy slices
If we define a new slice and set it equal to an existing slice, the new defined slice is of a reference type.
The correct way to make a separate copy of an existing slice is by using copy()
function, as below:
Another quick note is referencing new slice to an existing array, like below:
This will create a slice referencing myArray
. Modifying mySlice
will also modify myArray
.
4. slices equality
Since Golang 1.21, we can use a slices.Equal()
generic function from the standard library like below:
But In previous versions of Golang we could use reflect.DeepEqual()
.
5. slices and goroutines
slices in Golang are not thread safe. Passing slices without managing the potential race conditions will make our program to behave unpredictable.
We must use mutexes
to protect concurrency.
6. using append inside for loops
Using append
function inside a for loop can lead our program to a reallocation iteration and it will consume too much resource so we should avoid it as long as we can.
Preallocating with make()
function is a viable option when we are working with large datasets.
That’s it. Here is the summary of what we have reviewed so far about slices in Golang.
Summary
copy()
function makes a copy not a reference- Golang
1.21
representsslices.Equal()
- We should be careful about
for
loops andappend()
- Watch
goroutines
and race conditions - Use
make()
for preallocating slices
If you like this article please Clap 👏 and follow me to get more of these Golang contents.
ALSO READ: