Getting Started With Go Part 5: Pointers & Structs

This is part 5 in a series called Getting Started With Go. If you would like to check out parts 1-4 you may find them here:

  1. Part 1: Hello World
  2. Part 2: Variables & Constants
  3. Part 3: Functions
  4. Part 4: Arrays & Slices
  5. Part 5: Pointers & Structs (you are here now)

At this point we haven’t mentioned pointers yet, and if you’ve been following along we whipped up a struct or two on the fly but we never really really went into detail on them. Let’s get into both of those in detail now, starting with pointers. I will admit, coming from Android where pointers didn’t exist in Java or Kotlin, it took me a while to wrap my head around what pointers were. So before we talk about pointers, I think it would be beneficial if I explained how memory works in regard to storing data. 

Memory & Data

Let’s take a look at our yellow brick road of memory. You can think of each brick in the road as one box that can hold data.

Whenever we create a variable and assign some data to it like this:

a := 6

we are telling the compiler to store the number 6 inside of one of those yellow bricks of memory. We also named the yellow brick, “a”, therefore:

a := 6
b := 7
c := a + b

would look like this:

Now let’s take a look at where pointers come into the equation.

Pointers

Since each brick in the yellow brick road has its own address, similar to houses on a street, we are able to assign those addresses to another variable. Not the actual data, but the address of the data. We can point to that address by placing an & in front of the variable like this:

a := 6
b := &a

If we want to access what’s inside a from b then we would place a * in front of b, this is called de-referencing. 

c := b* + 7

One of the main benefits of pointers is being able to mutate a value that is passed into a function as a parameter.

type TinMan struct {
      Heart string
}

func main() {
    
    t := TinMan{ Heart: “Tin man has no heart.” }
    fmt.Println(t.Heart)
    GetHeart(&t)
    fmt.Println(t.Heart)

}

func GetHeart(tinMan *TinMan) {
    tinMain = “Tin man has a heart!”
}

If TinMan doesn’t get passed into GetHeart as a pointer, TinMan won’t ever have a heart :(. We should be familiar with how pointers work now, let’s talk about structs.

Structs

Structs, simply put, are Go’s version of objects. They are mostly used to combine a collection of relative fields into one place, we were off to a good start with our TinMan version.

type TinMan struct {
      Heart string
      Name string
      NeedOil bool
      Age int
     PlacesTraveled []string
}

Our TinMan has a little more data now. As part of part 3 of this blog series, we saw functions that had a receiver. If you didn’t happen to catch that article, receivers are a way to ensure certain functions can only be called by the respective struct.

func (t *TinMan) TravelToDestination(destination string) {
    If destination != ““ {
        t.PlacesTraveled = append(t.PlacesTraveled, destination)
    }
}

In the example above, we’ve set up a TinMan receiver on our TravelToDestination function. This is a simple function that will add a destination to the PlacesTraveled slice, as long as the destination isn’t an empty string. Also, the receiver type needs to be a pointer to a TinMan struct.

type TinMan struct {
      Heart string
      Name string
      NeedOil bool
      Age int
     PlacesTraveled []string
}

func (t *TinMan) TravelToDestination(destination string) {
    if destination != ““ {
        t.PlacesTraveled = append(t.PlacesTraveled, destination)
    }
}

func main() {
    t := TinMan{
          Heart:          "heart",
          Name:           "Ed",
          NeedOil:        false,
          Age:            13,
          PlacesTraveled: []string{},
    }

    t.TravelToDestination("here")
    t.TravelToDestination("there")
    t.TravelToDestination("everywhere")

    for i, _ := range t.PlacesTraveled {
        fmt.Println("destination", i, t.PlacesTraveled[i])
    }

}

If we put everything together and run the main function, we’ll see the following “here”, “there”, and “everywhere” print out to the console. However, if we made the receiver for TravelToDestination a normal TinMan struct, nothing would print out.

In this blog post we did a quick refresher on how memory works in regards to storing variables along with pointers and structs in Go. As always feedback is appreciated! I hope this post was of some value to you :).

2 thoughts on “Getting Started With Go Part 5: Pointers & Structs”

Leave a Comment

Your email address will not be published. Required fields are marked *