Not sure how to structure your Go web application?

My new book guides you through the start-to-finish build of a real world web application in Go — covering topics like how to structure your code, manage dependencies, create dynamic database-driven pages, and how to authenticate and authorize users securely.

Take a look!

A gentle introduction to Pointers

Published on:

When you assign a value to a variable in Go, the value is stored at a particular address in your computer's memory.

You can use the reference operator & to get this address, like so:

package main

import "fmt"

func main() {
    var answer int = 42

    fmt.Println(&answer) // Prints 0xc00001c030 or similar
}

When I run this code on my machine, it prints out 0xc00001c030, which is the memory address of the answer variable (expressed as a hexadecimal number). If you try running this code on your own computer, or on the Go playground, you'll probably get a different value.

What is a pointer?

When you use the & operator on a variable it actually returns a pointer.

In simple terms, a pointer is a variable that holds the memory address of another variable. You can think of them as "pointing to" a specific spot in memory.

Like the variables that they point to, pointers in Go also have types. A pointer with the type *int can only hold the memory address of an int variable. And a pointer with the type *string can only hold the memory address of a string variable. And so on.

That might sound a bit confusing, so to illustrate let's rewrite the example above so that we assign &answer to a variable instead of printing it directly. I'll use longhand variable declarations here (without type inference) to help make it explicit.

package main

import "fmt"

func main() {
    // Declare an answer variable with the type int and assign the value 42.
    var answer int = 42

    // Declare an answerPtr variable with the type *int. Use the & operator to
    // get a pointer to the answer variable and assign it as the value.
    var answerPtr *int = &answer

    fmt.Println(answerPtr) // Prints 0xc00001c030 or similar
}

So, in this example, the answerPtr variable is a pointer with the type *int, which contains the memory address of the answer variable.

We can re-write this to use the more common := shorthand operator for the variable declarations like so:

package main

import "fmt"

func main() {
    answer := 42

    answerPtr := &answer

    fmt.Println(answerPtr)
}

Dereferencing a pointer

You can use the dereference operator * to read or set the underlying value that a pointer points to. This is often known as indirection.

Here's an example of using the dereference operator to read an underlying value:

package main

import "fmt"

func main() {
    answer := 42
    answerPtr := &answer

    fmt.Println(answerPtr)  // Prints 0xc00001c030 or similar
    fmt.Println(*answerPtr) // Prints 42
}

Remember, the answerPtr variable in the example above points to the answer variable. By using the dereference operator *answerPtr we can 'read through' to get the value of the answer variable and print it out.

And we can also use the dereference operator to 'write through' and assign a new underlying value. Like so:

package main

import "fmt"

func main() {
    answer := 42
    answerPtr := &answer

    *answerPtr = 99     // Use the dereference operator to assign a new value
    fmt.Println(answer) // Prints 99
}