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 *