Golang Pointers and Functions: A Guide with Examples
Tags: go, programming, learning
Published: 2023-05-17 02:52:56

In this article, we'll explore how Golang pointers work in functions, and we'll provide examples of using them with and without memory references.

**What are Pointers in Golang?**

A pointer is a variable that contains the memory address of another variable. In Golang, a pointer is represented by an asterisk (*) followed by the data type of the variable it points to. For example, the following code declares a pointer to an integer variable:

```
var ptr *int
```
This declares a pointer named "ptr" that points to an integer variable. To assign the address of a variable to a pointer, use the "&" operator. For example:

```
var num int = 42
ptr = &num
```
This assigns the address of the "num" variable to the "ptr" pointer. Now, the "ptr" pointer points to the "num" variable in memory.

Using Pointers in Functions

When a pointer is passed to a function, the function can modify the value of the variable it points to directly in memory. This is much more efficient than passing a copy of the variable to the function, which requires creating a new variable in memory.

Let's take a look at an example:

```
func updateValueWithRef(chain *string) {
    fmt.Printf("%p\n", &*chain)
    *chain = "Hello from function"
}
```
This function takes a pointer to a string variable as its argument. Inside the function, we use the "*" operator to dereference the pointer and access the value of the variable it points to. Then, we can modify the value of the variable directly in memory by using the "=" assignment operator.

**With Memory References**

Now, let's take a look at an example of using a pointer with a memory reference:

```
chain := "Hello world"
fmt.Printf("%p\n", &chain)
fmt.Printf("Before function: %s\n", chain)
updateValueWithRef(&chain) // send a reference to the original
fmt.Printf("After function with pointer: %s\n", chain)
```
In this example, we declare a string variable named "chain" and assign it the value "Hello world". We then print the memory address of the "chain" variable using the "&" operator.

Next, we call the "updateValueWithRef" function and pass it a reference to the "chain" variable using the "&" operator. Inside the function, we modify the value of the variable directly in memory using the "*" operator.

After the function call, we print the value of the "chain" variable again, and we can see that it has been modified by the function.

**Without Memory References**

To understand the difference between using a pointer with and without memory references, let's take a look at an example of using a pointer without a memory reference:

```
func updateValue(chain string) {
    fmt.Printf("%p\n", &chain)
    chain = "Hello from function"
}
```
In this function, we take a string variable as its argument. Inside the function, we modify the value of the variable using the "=" assignment operator.

Now, let's call this function instead of the "updateValueWithRef" function in our previous example:

```
chain := "hello world"
fmt.Printf("%p\n", &chain)
fmt.Printf("Before function: %s\n", chain)
updateValue(chain) // send a copy, not reference
fmt.Printf("After function: %s\n", chain)
```
In this example, we call the "updateValue" function and pass it a copy of the "chain" variable. Inside the function, we modify the value of the copy using the "=" assignment operator.

After the function call, we print the value of the "chain" variable again, and we can see that it has not been modified by the function.

Full code example:

```
package main

import "fmt"

func main() {
	chain := "Hello world"
	fmt.Printf("%p\n", &chain)
	fmt.Printf("Before function: %s\n", chain)
	updateValue(chain) // send a copy, not reference
	fmt.Printf("After function: %s\n", chain)
	updateValueWithRef(&chain) // send a reference
	fmt.Printf("After function with pinter: %s\n", chain)
}

func updateValue(chain string) {
	fmt.Printf("%p\n", &chain)
	chain = "Hello from function"
}

// TODO - pointers *
func updateValueWithRef(chain *string) {
	fmt.Printf("%p\n", &*chain)
	*chain = "Hello from function with ref"
}

/*
	Output:
	0xc00009e230
	Before function: Hello world
	0xc00009e250
	After function: Hello world
	0xc00009e230
	After function with pinter: Hello from function with ref
*/
```

**Conclusion**

In conclusion, pointers are a powerful feature of Golang that enable developers to write more efficient code by manipulating data directly in memory. When using pointers in functions, it's important to understand the difference between using them with and without memory references, as this can affect how the function modifies the value of the variable it points to.

By understanding how pointers and functions work together in Golang, developers can write more efficient and scalable code that takes advantage of the language's unique features.