Go Pointers! Let’s talk about it…

23 / Jan / 2023 by shivang.chaturvedi 0 comments

A pointer, as name suggests, is a variable that points to a location in the memory of your system where a value is stored rather than a value itself. Basically, it is an address to the value stored in memory. The definition is simple but this concept can be a little tricky to wrap your head around.

When I first developed a good understanding of pointers in Go, I asked myself, “How can I explain this concept to a 5-year-old?” Well, I don’t know if I can find words to explain this to a 5 year old, but I will still attempt to give you a simplistic and comprehensive understanding.

Let’s write a small piece of code:

package main

import "fmt"

type animal struct {
name string
sound string
}

func main() {
myAnimal := animal{
name: "Cat",
sound: "Meeeaaawwwwww",
}

myAnimal.updateAttributes("Cow", "Mooooooooo")

myAnimal.print("Updated Structure")
}

func (p animal) updateAttributes(newName string, sound string) {
p.name = newName
p.sound = sound
}

func (p animal) print(text string) {
result := fmt.Sprintf("%s ==> %+v \n \n", text, p)
fmt.Printf("%+v", result)
}

Let’s break this down:

  1. We are creating an animal, cat which has attributes defined in type animal .
  2. Now, I want to update myAnimal from a cat to a cow. To do so, I am calling my receiver function cat.updateAttributes("cow", "mooooooooo") to update the attributes name and sound .
  3. Finally, I have invoked another receiver function print to print my updated animal.

Let’s run our go module using go run .:

//Output:

Updated Structure ==> {
name:Cat 
sound:Meeeaaawwwwww 
zooInfo:{
town:California 
email:abc@xyz.com 
pinCode:12345
  }
}

Wooops… as you can see, my animal is still a cat.

Let’s see what gets printed inside the receiver function:

func (p animal) updateAttributes(newName string, sound string) {
p.name = newName
p.sound = sound

// Let's call the print command here!
p.print("Tadaaa")
}

//Output
Tadaaaa ==> {
name:cow 
sound:Mooooooooo 
}

Here is what happens in the background:

In nutshell, Go creates an entirely new struct when a myAnimal is passed from one function to another and p , the receiver function argument becomes a new struct altogether.

In other words, p has its value stored in a different memory location than myAnimal .

For making changes in the original struct , we can use * and & operators.

The ‘*’ and ‘&’ operator

Let’s modify our main function and receiver function updateAttributes a bit:

func main() {
myAnimal := animal{
name: "Cat",
sound: "Meeeaaawwwwww",
}

//STEP#1. Print the original struct myAnimal
myAnimal.print("Original Structure")

//STEP#2. Create a pointer
myAnimalPointer := &myAnimal

//STEP#3. myAnimalPointer will still have access
//to receiver functions of myAnimal.
//So let's update myAnimalPointer value attributes
myAnimalPointer.updateAttributes("Dog", "Woof Woof Woof")

//STEP#4. Print the myAnimal values and see if the 
//original struct values changed
myAnimal.print("Updated Struct")
}

//STEP#3.1: We'll access the value attributes using * operator 
//and make the changes in the orginal struct value
func (p *animal) updateAttributes(newName string, sound string) {
(*p).name = newName
(*p).sound = sound
}

Let’s talk about “main” function: Creation of a pointer

myAnimal := animal{
name: "Cat",
sound: "Meeeaaawwwwww"
}

myAnimalPointer := &myAnimal
myAnimalPointer.updateAttributes("Dog", "Woof Woof Woof")

//OR We can simply do something like 
(&myAnimal).updateAttributes("Dog", "Woof Woof Woof") //Same thing!

myAnimal.print("Updated Struct")
}

Using the &operator, we can create a pointer and we can get the address in memory where the value of the myAnimal is stored. We have assigned &myAnimal pointer to myAnimalPointer variable.

Let’s talk about the receiver function “updateAttributes” : Retrieving value from the pointer

func (p *animal) updateAttributes(newName string, sound string) {
(*p).name = newName
(*p).sound = sound
}

p is the pointer that function receives when invoked.

*animal is not a pointer but a mere description of what this function expects when invoked.

The value in memory that pointer p references to, can be accessed using the * operator.

Using brackets, (*p), will give you the access to the struct attributes.

Let’s run the code again:

go run .

//Output
Original Structure ==> {name:Cat sound:Meeeaaawwwwww}

Updated Struct ==> {name:Dog sound:Woof Woof Woof}

Woohooo 🎉… we have updated the original struct myAnimal with the power of pointers.

A Gotcha moment…

“abracadabra”, let the code appear…

func main() {
myAnimal := animal{
name: "Cat",
sound: "Meeeaaawwwwww",
}
myAnimal.print("Original Structure")

//Let's comment the 2 lines below

//myAnimalPointer := &myAnimal
//myAnimalPointer.updateAttributes("Dog", "Woof Woof Woof")

//Let's use our same old myAnimal struct without creating a pointer 
myAnimal.updateAttributes("Dog", "Woof Woof Woof")

myAnimal.print("Updated Struct")
}

func (p *animal) updateAttributes(newName string, sound string) {
(*p).name = newName
(*p).sound = sound
}

Go automatically takes care of pointer creation in the background so that you don’t have to. And that’s how, you will get the same result:

go run .

Original Structure ==> {name:Cat sound:Meeeaaawwwwww}

Updated Struct ==> {name:Dog sound:Woof Woof Woof}

The new Keyword

Lets create a pointer using a new keyword:

package main

import "fmt"

type animal struct {
name string
sound string
}

func (p *animal) updateAttributes(newName string, sound string) {
(*p).name = newName
(*p).sound = sound
}

func main() {
// LOOK OVER HERE!!!

myAnimal := new(animal)
myAnimal.updateAttributes("Dog", "Woof Woof Woof")
fmt.Printf("%+v", *myAnimal)

}


//Output:
{name:Dog sound:Woof Woof Woof}%

Official Definition:

The new takes type as an argument, allocates enough memory to fit a value of that type and returns a pointer to it.

I hope, I was able to make this concept a little easier to grasp for all my lovely readers and followers like yourself. If you feel, something can be improved, please drop a comment and I will look into it.

Have a lovely day!

. . .

Note of thanks ❤️

Thank you for stopping by. Hope, you find this article useful. Please follow me on medium and help me reach 1k followers 🙏🏻. That will truly encourage me to put out more content.

P.S.: If you feel something can be improved or lacks proper explanation, drop me a note in the comment box or mail me at shiva.chaturvedi91@gmail.com. After all, you can teach me a thing or two as well.

 

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *