Today's Question:  What does your personal desk look like?        GIVE A SHOUT

Understanding Slice Behavior in Go

  sonic0002        2024-03-10 06:43:51       386        0    

In Go, understanding how slices behave when passed to functions is crucial for writing efficient and bug-free code. This behavior is often a source of confusion for many developers, especially those new to the language. In this article, we'll explore the difference between passing slices by value and by reference, and how it impacts the modification of slices within functions.

Introduction

In Go, slices are a fundamental data structure used to work with sequences of elements. They are essentially a view into an underlying array, providing a flexible and powerful way to manipulate collections of data. However, the way slices are handled when passed to functions can sometimes lead to unexpected behavior if not understood correctly.

Pass by Value

When a slice is passed to a function in Go, it is passed by value. This means that a copy of the slice header, which includes the pointer, length, and capacity, is created and passed to the function. Let's consider the following example function:

Let's start by examining what happens when we pass a slice to a function by value. Consider the following function:

func set3(a []int) {
    a[1] = 3
}

In this function, we are attempting to set the value at index 1 of the slice a to 3. Because slices are passed by value in Go, a copy of the slice header is passed to the function, including a pointer to the underlying array. Modifications made to the elements of the slice within the function will affect the original slice outside of the function.

Hence the output for below code snippet would be [1 3 3 4 5].

package main

import (
	"fmt"
)

func main() {
	var a = []int{1, 2, 3, 4, 5}

	set3(a)

	fmt.Printf("%+v\n", a)
}

func set3(a []int) {
	a[1] = 3
}

In this example, the value at index 1 of the original slice a is modified to 3 inside the set3 function. When we print the a after calling set3, we see that the modification is reflected in the original slice.

Now what if an element is appended to the passed slice?

func add3(a []int) {
    a = append(a, 3)
}

What would happen to slice a?

package main

import (
	"fmt"
)

func main() {
	var a = []int{1, 2}

	add3(a)

	fmt.Printf("%+v\n", a)
}

func add3(a []int) {
	a = append(a, 3)
}

Would it print [1 2 3] or [1 2]?

In this function, we attempt to append the number 3 to the provided slice a. However, since a is passed by value, any modifications made to it within the function are local to that function's scope. The original slice passed to add3 remains unchanged after the function returns. This remains true though slice is backed by array in Go.

Pass by Reference

To modify the original slice within a function, we can pass a pointer to the slice. This way, the function receives a reference to the original slice, allowing it to directly modify the underlying array. Here's an example function:

func add4(a *[]int) {
    *a = append(*a, 4)
}

In this function, we receive a pointer to a slice a, and we append the value 4 to the slice pointed to by a. Because we are modifying the original slice through the pointer, the changes will be reflected outside the function.

Conclusion

Understanding how slices behave when passed to functions is essential for writing correct and efficient Go code. By recognizing the difference between pass by value and pass by reference, developers can avoid common pitfalls and write more predictable code. Remember, slices are passed by value, but because they reference underlying arrays, modifications made within functions can affect the original slice if passed by reference.

ARRAY  SLICE  PASS BY REFERENCE  PASS BY VALUE 

Share on Facebook  Share on Twitter  Share on Weibo  Share on Reddit 

  RELATED


  0 COMMENT


No comment for this article.