DEV Community

Ian
Ian

Posted on

Trying to understand pointers in Go - What is a pointer anyway?

Over the past couple of months, Go has taken my interest. As I worked through different tutorials and made small projects I noticed an area that was a conceptual gap: pointers. My first language was Java. Since then I've worked in various languages like Groovy, Javascript, and Python. All of the languages I had worked in didn't have this feature or it was hidden away as was with Java (In Java the object type stores a reference to an object, which is just a pointer, more on that here).

These are my personal notes for learning pointers in general and more specifically in Go. I've linked some of the sources I used in the bottom of the post. They do a much better job than I did, so please check them out!

What is a pointer?

As Professor Dave Marshal defines it here "A pointer is a variable which contains the address in memory of another variable". So pointer points to a memory address. When a variable is created it is stored in memory. When a pointer is declared for that variable it "points" to where that variable is in memory.

That's nifty, so what?

What advantage would it be to pass a memory address as opposed to passing a value? Is this just adding more complexity? Let's look at an example:

func main() {
    j := 12
    fmt.Println(j)
    changeJ(j)
    fmt.Println(j)
}

func changeJ(j int) {
    j = 30
    fmt.Println(j)
}

The result?

12
30
12

This is because the function changeJ() doesn't actually change the variable j in the context of the main() function. Let's change changeJ() to return an int.

func main() {

    j := 12
    fmt.Println(j) 
    j = changeJ(j)
    fmt.Println(j) 
}

func changeJ(j int) int{
    j = 30
    fmt.Println(j)
    return j
}

The result?

12
30
30

Because we are setting j to the value returned by changeJ() now we see j has the updated value. How could we potentially do this with a pointer?

Pointers in Go

Pointers in Go are denoted by * and & followed by the variable that it is pointing to.

* denotes the value of what is in the memory address that it pointer is pointing to.

& denotes the address location of where the pointer is pointing to. This returns the location in memory.

So if we have j := 12 and we want to point to the value of j we would use the symbol *j. If we want to point to the memory address of j we would use &j. Let's look at the following snippet.

func main() {
    j := 12
    fmt.Println(j) 
    k := &j
    changeJ(k)
    fmt.Println(j) 
}

func changeJ(j *int) {
    *j = 30
    fmt.Println(*j)
}

The result?

12
30
30

By setting the value of the pointer we can directly change the value of the variable in its memory address. No return statement needed to set a variable or to hold the results of the changeJ() in the main() function.

When to use pointers

When should we use pointers? In the faq's page for Go it lays out some use cases:

  1. "...does the method need to modify the receiver? If it does, the receiver must be a pointer."

  2. "If the receiver is large, a big struct for instance, it will be much cheaper to use a pointer receiver". So it is less intensive to pass the address of the memory than to pass a large copy.

  3. "If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used".

Credit where credit is due: Things I found helpful

  1. Pointer Receivers - Go Lang Practical Programming Tutorial p.8

  2. A Tour of Go: Pointers

  3. Pointers - DaveMarshall

  4. Go FAQs

  5. David J. Eck - Appendix 1, Section 2
    Pointers and Arrays in C++

Top comments (0)