blog/content/post/learning-go-pointer-receivers.md

111 lines
4.0 KiB
Markdown

---
title: "Learning Go: Pointer Receivers"
date: 2017-12-29T10:46:08-05:00
draft: false
tags: ["golang", "learning"]
---
# I gotta get Go-ing with this language
Being in the position I am, I've worked with almost nothing but exclusively interpreted languages, namely Ruby and Python.
Both of these are great tools to have to solve problems and to solve them quickly. It is easy to pick up an idea and get
a prototype going in Python or Ruby due to not having to run any compilation, code changes can be tested instantly often by
just rerunning the interpreter. However, this can be a problem when programs get large. I've been a part of projects
where there are hundreds of thousands of lines of Ruby and Python code where changes to some backend call can cause a ten second
difference in the load time of the frontend client.
![Image](/img/post/golang.gif)
People much smarter than me at Google have created and actively develop the programming language Go, which is a compiled language
that does a lot of cool things out of the box. Knowing how many problems I've had in development that could be potentially solved by Go
(and missing compilers which catch some nasty bugs before the software starts), I want to learn Go and blog about cool things I find or cool
things I do with it.
## Pointer Receivers?
These are a neat way of providing methods for structures or builtin types that modify whatever the pointer points to.
So we've got these people right? And people in this universe are very simple. All they have to identify them is their name, their astrological sign
and their disposition.
```go
type Person struct { name, sign, disposition string }
```
Now a person's name may not change, nor their sign, but what about their disposition? I'd say my average day is an emotional rollercoaster! Only kidding,
but we need a way to operate on the person's disposition, let's say based on weather.
```go
func (p *Person) AlterDisposition(weather string) {
switch weather {
case 'rainy':
p.disposition = "sad"
case 'sunny':
p.disposition = "happy"
default:
p.disposition = "meh"
}
}
```
That's a funky syntax, but what that first parameter looking piece is right after `func` is a pointer receiver. You can think of this like being `self` for
Ruby or Python. It refers to whatever type we are adding this method to, but the nice thing about a pointer receiver is that we are modifying the structure that
`p *Person` points to vs. everything just being copies in local scope. Let's see this in action.
```go
package main
import "fmt"
type Person struct { name, sign, disposition string }
func (p Person) GetDisposition() string {
return p.disposition;
}
func (p *Person) AlterDisposition (weather string) {
switch weather {
case "rainy":
p.disposition = "sad"
case "sunny":
p.disposition = "happy"
default:
p.disposition = "meh"
}
}
func main() {
var p Person = Person{ "Jake", "Sagittarius", "happy" }
fmt.Println(p.GetDisposition());
p.AlterDisposition("rainy")
fmt.Println(p.GetDisposition());
}
```
The output of building and running this program is this:
```
happy
sad
```
You can see that our little Jake person got upset that it started to rain, and the pointer receiver works as expected, altering our original
`Person` object.
A few notes about the pointer receivers.
1. Receivers may only use named types
Receivers are the first part of the function signature directly after the func keyword
```go
func (receiver Receiver) Method() {...}
```
And the receiver MUST be a named type (structs, type definitions etc.). Also the receiver cannot be a named type that is itself a pointer.
2. Style conventions are that if any pointer receiver is required, then all methods should have pointer receivers.
It is technically possible to have methods for both pointer receivers, and regular receivers, but you should only have pointer receivers if you need
even just one of them for a given type.