This is my second article since I started learning the go programming language. If you're also getting your feet wet with a statically typed and compiled language like Go for the first time, this article will help you understand the what and why of pointers.
What are pointers?
Pointers, in computer programming, are simply objects that store memory addresses. A memory address is a reference to a specific location in memory. Think of it as physical addresses, you can easily access a particular location on a map if you had the address right? The map here is the computer memory layout where you store variables of different types each referenced by a unique address.
Why pointers?
By now you must be wondering what is the significance of pointers. Pointers are particularly useful in repetitive operations like working with iterables or working with multiple copies of the same underlying data. It is much faster and less expensive to copy over a pointer to a variable and also to deference it rather than copying the whole data structure itself.
Let's say you have an array of 10,000 items and you want to make a duplicate, copying over an array of such size is not only less efficient but will also be significantly slower than copying a memory address. Imagine you had to make up to 3, 4, or even 10 copies, it's starting to look silly.
NB: Dereferencing means fetching the value stored at a memory location by a pointer.
While pointers are not explicitly available in every programming language, a similar concept like the reference data type is used rather than pointers in languages like JavaScript, Java, Python. The benefit of pointers is that it removes the layer of abstraction that comes with references and allows the developer explicit access to memory addresses.
Pointers in Go
Go, like C and C++ gives us pointers to work with. The syntax is similar to C but with a little difference. This is how you define a pointer in Go:
In the snippet above, we define a variable called name
(very thoughtful) and set the value "John Travolta". We also define another variable pointerToName
which is literally a pointer to the variable name
. The "&" symbol preceding name
essentially says: "give me the memory address of this variable". If we print both variables, we see that name
outputs the value of the variable while pointerToName
outputs the memory address of the variable name
.
So how do you dereference (i.e fetch the underlying value of a memory address) a pointer in go? Before we look at the syntax, it's worth noting that go is a pass-by-value language. This means that when we pass variables around (e.g to a function or assigning an existing variable to another variable declaration), the value is copied to a different memory location and is no longer tied to the original copy. If we mutate the duplicate data, the original copy maintains its state.
This is what is known as passing by value. Of course, the opposite happens when you pass by reference.
Although, not all data types are passed by value.Slices
,maps
,channels
,functions
and of coursepointers
are reference types whileints
,floats
,strings
,bools
, andstructs
are value types. It is worth noting especially when working with structs to build more complex data structures.
Consider the following snippet:
What's happening here? We're simply defining a struct that describes a user with 4 fields. We declare a variable user1
of type User and set the field values. We declare a new variable user2
by copying user1
then we update the age field. From the output of the two variables, we see that the age field remains unchanged for user1
while user2
is updated. Moving on, we declare a third variable, wait for it, user3
and set it to be a pointer to user1
. Now, we do the same thing by updating the age and isAdmin fields and from the output, we see that these files were updated for both user1
and user3
.
The "*" symbol preceding
user3
in thefmt.Printf()
function is how we dereference pointers. We're essentially saying: "give me the value stored at this memory address". This is the reverse use case of the "&" symbol.
In conclusion, we can observe that our data structure wasn't mutable by default and we had to explicitly mutate it through pointers which is a good safety measure. This is an introduction to pointers, however, there's more to it like its usage in receiver functions and double pointers. You can read more about pointers in Go here and here.
Top comments (0)