This was originally submitted to Flashreads.
Mutating slices in Go can be a bit confusing.
It’s generally known that slices are a reference an underlying array. But when it comes to mutating a slice, there are some very common gotchas that can trip you up. Let’s look at three scenarios.
From inside a function
In Go, all variables are passed by value, meaning the function body will receive a copy.
When you pass a slice to a function, the variable (slice descriptor), is a copy of the caller’s reference to the underlying array (by caller
I mean the place where the function is being called).
So if you try to append to the slice inside the function, you are actually appending to a duplicate of the original reference. The caller’s slice will remain unaffected.
In the example below, we try to append a value to a slice, using the addNum
function. Unfortunately, after calling addNum
, the slice hasn’t changed.
|
|
To successfully append to the slice, the function must return its copy of the slice. You then assign it to the original slice.
|
|
From inside a for-loop
When ranging over a slice, the variable referencing each value points to a copy of the value. If you try to mutate the value at a given index with this variable, it will not work. Once you leave the scope of the for-loop, you’ll find the slice was unaffected.
|
|
For the mutation to stick, you must use bracket notation instead:
|
|
When using variables
This is similar to the for-loop example. Any changes to a slice require the use of bracket notation. Variables will point to copies of the value at a given index, meaning any changes to that variable will not affect the slice.
|
|
With bracket notation, it works.
|
|