Getting started with Go Part 3: Functions

Now that we’ve completed our hello world exercise in part 1 and played around with variables and constants in part 2, let’s take it a step further and learn how functions work in Go. But first, what is a function?

Functions

Functions are chunks of code that are run in sequence and typically perform some type of routine or action. I like to use them for a number of reasons, one of the main ones is keeping my code readable and maintainable. Functions can be big or small, complex or not. They’re able to  take in information via different arguments and returning information. 

Imagine we were building a rocket ship and wanted it to be able to fly to a different planet as well as hold a few cab members. Let’s look at how we can create some functions to do that. Create a fresh project, name it whatever, and create a file called main.go. I named my project, “space-travel”. We’ll start by building some functions that will give us information on the cab members.

package main

type Rocketship struct {
  Pilot    string
  CoPilot  string
  Engineer string
}

func (r Rocketship) AddPilot(pilotName string) {
  r.Pilot = pilotName
}

func (r Rocketship) AddCoPilot(coPilotName string) {
  r.CoPilot = coPilotName
}

func (r Rocketship) AddEngineer(engineerName string) {
  r.Engineer = engineerName
}

We start with a Rocketship struct that contains a few strings to hold the information for a pilot, co-pilot, and engineer. If you don’t know what a struct is that’s okay, for now we just want to focus on the fact that it has some fields that are string types. Below, there are three functions. Let’s go over one of them. Starting from the left, we have the word func (short for function) which is a keyword in the Go language. If you want to create a function it has to start with this.

Next we have (r Rocketship) which is basically saying that only a Rocketship struct can use this function and if we wanted to reference the Rocketship that is calling the function, we can do so through r. Next is the name, GetPilot. Because this function doesn’t take any arguments, the parenthesis to the right of AddPilot is empty. Finally, we have a set of brackets with a line of code inside that prints out the name . Any line of code in between the brackets will be executed every time this function is called. 

After that, we have two more functions that do the same thing, except for the co-pilot and engineer on rocket ship. Let’s make use of these functions by creating a Rocketship struct in the main function and adding some members. Add this to the bottom of main.go:

func main() {

  rocketShip := Rocketship{
     Pilot: "Pilot name here",
     CoPilot: "Co-Pilot name here",
     Engineer: "Engineer name here",
  }

  rocketShip.GetPilot()
  rocketShip.GetCoPilot()
  rocketShip.GetEngineer()

}

When we run this file now, we see whatever names we passed into the Rocketship fields get printed out (or “Pilot name here”, etc. if you didn’t make any changes.). These are some rather simple functions, though, they’re one liners. That’s not bad, but more often than not, functions of real world use are multiple lines, take arguments, and may return a value or two. Let’s try something that achieves the mentioned criteria.

func (r Rocketship) VisitMars(pilotName string, daysOnTrip int) (string, error) {
  fmt.Printf("Preparing %s for visit to Mars....\n\n", pilot)

  fmt.Println("This trip typically takes 5 days.")

  if daysOnTrip < 1 {
     return "", errors.New("Days on trip less than 1")
  }

  if daysOnTrip <= 5 {
     return fmt.Sprintf("%s made it back safely!", pilot), nil
  } else {
     return fmt.Sprintf("Oh no! We've lost contact with %s! Send backup!", pilot), nil
  }
}

So let’s break this down line by line. Similar to the previous function, we start with the keyword func, a receiver (r Rocketship), and a name. However, this time we are taking some arguments in the parenthesis to the right of the function name, pilotName of type string and daysOnTrip of  type int. After that, there’s a second parenthesis with two types inside, string and error. This is how Go returns multiple values for one function. If we were only returning one value, we wouldn’t need the parenthesis. 

Next, is the body where we have a few print lines, a basic error check, and control flow. On the first line of VisitMars, we print out a status message in a formatted string. Next is an informational message about how much time the trip typically takes. And after that is a basic error check to make sure the number of days passed into the function is at least one. If it is less, then we’ll return an error. Since this function returns a string and an error object, both items have to be returned anytime the function returns a value. In the error check, you can see we return an empty string along with our error message. Our error object has its own string to communicate the error message.

For the final part of this function, we have what is called a control flow check. The reason is because we are controlling the execution flow of the code by deciding which part of the code will execute through the if statement. If daysOnTrip is 5 or more, we will print one thing. If not, we will print something else. In this case, we see it is beneficial to send our pilot on a trip of at least 5 days or they may not return! 

Oh no! We've lost contact with Ed! Send backup!

Can you think of any more functions to add? Maybe something that will take us to a different planet? Or maybe a function that will build an even bigger rocket ship? The sky’s the limit! In this post we learned how to create functions and return values. Feel free to look into returning different kinds of data types or adding some more robust logic to our VisitMars function. As usual, if you have any questions, comments or concerns, feel free to get in touch. Thanks!

Leave a Comment

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