Slices and arrays are among the most commonly used data structures in Go. Despite similar syntax, the difference in their structure and behavior can lead to performance, memory, and semantic errors.
Background:
Go has chosen an explicit memory management model from the very beginning, in which arrays are a sequence of elements of fixed size, while slices are a dynamic view on the array. This separation allows controlling the cost of operations and code behavior.
Problem:
The main challenge is the confusion between array copying (value semantics) and the "referential nature" of slices. Errors often occur when passing these types to functions and modifying values, leading to unexpected side effects.
Solution:
Arrays are always copied when passed by value: the function receives a copy of the entire content. A slice, however, is a small structure (header) that contains a pointer to the array, length, and capacity. Changes within the slice are visible outside if the content of the array is modified (but not if the slice itself is redirected to a new array within the function).
Code example:
func updateArray(arr [3]int) { arr[0] = 10 } func updateSlice(slc []int) { slc[0] = 10 } func main() { a := [3]int{1,2,3} b := []int{1,2,3} updateArray(a) updateSlice(b) fmt.Println(a) // [1 2 3] fmt.Println(b) // [10 2 3] }
Key features:
What happens if you change the length of the slice inside a function? Will it affect the original slice?
No, changing the length of the slice (for example, using slc = slc[:2]) inside the function will only affect the local copy of the header. The original slice will remain unchanged.
Does the append operator return the modified slice in the same memory area?
Not necessarily. If there isn't enough capacity, a new array is created and a pointer to the new array is returned. The old array will remain unaltered.
Code example:
s := []int{1,2,3} s2 := append(s, 4, 5, 6) // s2 may be in a new memory area
Can you assign an array to a slice or vice versa?
No. []int and [5]int are different types. To pass an array as a slice, you need to use the conversion arr[:]. The reverse is not possible.
A junior developer implemented a table update function by passing an array to the function with the expectation that the changes would be applied to the original array. The modifications were not "saved".
Pros:
Cons:
The function accepted a slice and explicitly returned a modified copy, enhancing the predictability of the effect. All changes were conscious, data did not "leak" and was not modified implicitly.
Pros:
Cons: