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:
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:
&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:
For example:
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:
p = &i // makes p point to the address of i
Reading pointer values
To read the values of our pointers we use the * operator:
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:
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:
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:
Is p assigned? true
Comparing pointers
Can we compare pointers? Definitely, by using the & operator:
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.