Tuesday, March 2, 2021

Pointers in Go

Understand all about declaring and using pointers in Go

If you're coming from Python, Java, JavaScript, C# and others, talking pointers may scare you. But fear not! Go's approach to pointers is very elegant and definitely very easy to understand.

Variables

We cannot talk pointers without understanding variables. Every variable you declare in Go (or any programming language for that matter) is essentially a way to identify a block of memory that contains a value assigned to it.

There are multiple ways to declare variables in Go. For example:

package main

import "fmt"

func main() {
     var name = "John Smith"
     var email string = "john@smith.com"
     fmt.Printf("Name: %v, Email: %v", name, email)
}

We could have used the & operator to access the memory addresses of our variables:

fmt.Printf("&name: %v, &email: %v", &name, &email)
&name: 0xc00010a040, &email: 0xc00010a050

Pointers

But what about pointers? Pointers are nothing more than variables that hold the memory address of a value. In other words, the location at which a value is stored. In Go, the * character is used to either declare and read the value of a pointer For example, The type *T is a pointer to a T value.

The zero value for an unassigned pointer is always nil.

Declaring Pointers

To declare pointers, use the * character preceding its type. Like variables pointers have to be declared before they are accessed following this syntax:

var myVar *type

For example:

var p *int // declares a pointer to int

Assigning values to pointers

To assign values to pointers, you should point it to the address of another variable. That's done by using the & operator we saw previously:

i := 22 // assigns 22 to i (i is an int)
p = &i  // makes p point to the address of i

Reading pointer values

To read the values of our pointers we use the * operator:

fmt.Println(*p) // read i through the pointer p
What you see above is called "dereferencing" or "indirecting".

Nil Pointers

Since in Go you cannot declare and set a value to pointers, by default, every unassigned pointer has its zero values set to nil. The nil pointer is a constant with a value of zero as we can see in the example below:

q *int
fmt.Printf("Q: %v %x", q, q)
Q: <nil> 0

But what happens if we try to access its value before we use it? Yes, an error:

fmt.Println("Q: %v", *q)

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4990a3]

Checking if a pointer is assigned

To check if a pointer has been assigned to, you could compare it to nil. True means your pointer is assigned to a memory address and it's safe to access its value:

fmt.Println("Is p assigned?", p != nil)
Is p assigned? true

Comparing pointers

Can we compare pointers? Definitely, by using the & operator:

var x, y int
fmt.Println(&x == &x, &x == &y, &x == nil)
true false false

When use Pointers

So when should you use pointers? Since pointers allow accessing variables indirectly you may think that whenever you need to access your values. But the rule of thumb is that you should use pointers for sharing data - whenever you want an external function to be able to modify your data.

Limitations of Pointers

If you're coming from C, there's one important detail. Go unlike C, Go has no pointer arithmetic. 

Conclusion

On this post we learned about pointers in Go. If you're coming from Python, Java, JavaScript, C# and others, talking pointers may scare you. but fear not! Go's approach to pointers is very elegant and definitely very easy to understand.

Remember, that pointers make your code a little less legible so use them whenever you need to share some value.

See Also

Any comment about this page? Please contact us on Twitter

Featured Article

Pointers in Go

Understand all about declaring and using pointers in Go If you're coming from Python, Java, JavaScript, C# and others, tal...

Popular Posts