November 1st, 2024
Pointers are one of the important features in Go. It enables performance, manage memory effectively, and provide flexibility on how data structures and functions interact. But then, what are pointers?
Pointers are simply variables that store value addresses instead of values. In a real-world example, compare pointers to a home address: just as an address points to a house location, a pointer in Go points to a specific memory location holding a value. You can also think of it as a signpost that points to a specific location in your computer’s memory where value is stored.
By default, Go creates a copy when passing values to functions. For huge and complex values, this may take up too much memory space unnecessarily. With pointers, only one value is stored in memory(and the address is passed around). Pass a pointer (address) instead of a value to a function. The function can then directly edit the underlying value—no return value is required.
Now that we know what pointers are, let see how to use them in Go.
Let's declare a pointer and access the value.
In the above code, we declared a variable number and assigned a value 42, then created a pointer numberPointer to number. By deferencing *numberPointer, we access the value of number i.e 42 through the pointer.
One important thing to note in Go is that all values have a so-called "Null Value" i.e., the value set as a default if no value is assigned to a variable. For example the null value of an int variable is 0, for a float64 it is 0.0, and for a string value it's " ". For a Pointer, the null value is known as "nil"
We have successfully seen a basic example of how to use pointers in Go, now let's look at more practical use cases.
Function Parameters: - passing large structures to functions by pointer can improve efficiency.
Instead of passing a copy, we pass the address of num, so the function can directly modify its value.
Mutating Data with a Pointer: - pointers in Go enables direct data mutation of variables, struct and arrays by referencing their memory locations. Instead of passing a copy of data to a function or operation, a pointer gives access to the original data.
In the above example, num is a pointer to the value in incrementByTen function. By dereferencing (*num), the function directly accesses and modifies the original value in main, value is updated to 15 after calling the function, showcasing direct mutation.
Using Pointers with Structs: - Using pointers with structs in Go allows you to modify the original struct data directly within a function, rather than working with a copy.
Passing a *Person pointer allows updateAge to modify person's fields directly.
Dereferencing nil Pointers: Trying to access or modify a nil pointer causes runtime errors. To resolve this, always check for nil pointer before dereferencing it to prevent errors.
Uninitialized Variables and Zero Values: using uninitialized variables without realizing they default to their zero values. To resolve this, initialize variables explicitly if needed.
Ignoring Errors: - using _ to ignore errors without checking. Always handle errors properly by checking for errors
We successfully learned how to create and use pointers in Go but what is very important to note is that it's not in all situations, we use pointers. So when and how do we use pointers?
Use pointers for large data structures that don’t need to be copied (e.g., structs in function parameters).
Avoid pointers for small values where a copy is more efficient.
Use nil checks where necessary, and always handle pointers carefully to avoid unexpected behavior.
Happy Coding! 👨🏽💻