💻 Tech
In Go, there are two data semantics: value and pointer semantics.
Value Semantics
Everything in Go is passed by value. This means that when you pass a literal or a variable to a function, the function receives a copy of the value. Changes made to this copy do not affect the original value. For example:
package main
import "fmt"
func main() {
var x int
fmt.Println(x) // Output: 0
func1(x)
fmt.Println(x) // Output: 0
}
func func1(x int) {
x++
}
In the above example, when x is passed to func1, the function gets its own copy of x. Incrementing x inside func1 does not change the original x in main.
Pointer Semantics
To allow a function to modify the original variable, you pass a pointer to the variable rather than the value itself. This is called pointer semantics. By passing a pointer, you allow the function to operate on the original data. Here’s how you can modify the previous example to use pointer semantics:
package main
import "fmt"
func main() {
var x int
fmt.Println(x) // Output: 0
func1(&x)
fmt.Println(x) // Output: 1
}
func func1(x *int) {
(*x)++
}
In this example, func1 takes a pointer to an integer (*int). Inside func1, we dereference the pointer (*x) to increment the original x from main.
Stack and Program Boundaries
When a goroutine transitions to another function call (a program boundary), it carries a stack frame where the values are accessed and manipulated. Each function call creates a new stack frame, and when the function returns, the stack frame is destroyed, and any changes to local variables within that stack frame are lost. This is why changes to the copy of a variable in a function do not affect the original variable outside the function when using value semantics.