ado.xyz

Golang Cheatsheet: Functions

May 1, 2020

Go or Golang is a fairly simple but extremely powerful programming language. In this post, we are going to become pros at working with functions in Go.

Functions: Making the World Go ‘Round

Functions in Go, much like variables, are easy to pick up and master but offer some unique features and functionality not commonly seen in other programming languages.

There is a lot of ground to cover here ranging from multiple return values from functions, anonymous functions, and variadic functions, so let’s dive right in.

Cheatsheet TL;DR

This cheetsheet is a quick summary of how to work with different functions in Go. Please note that this particular piece of code will likely not compile and is meant to be a quick glance reference.


// Function takes no params, returns nothing

func hello(){
  fmt.Println("Hello")
}

hello()

// Function takes one string argument, returns nothing

func hello(message string){
  fmt.Println(message)
}

hello("Hi there!")

// Functions takes no params, returns one string value

func hello() string {
  return "Hello"
}

greeting := hello()

// Function takes one string param, returns one string value

func hello(message string) string {
  return message
}

greeting := hello("Hi there!")

// Function accepts multiple params of various types
// Returns multiple values

func hello(message string, intensity int) (string, int) {
  return message, intensity
}

greeting, hypeLevel := hello("Hi there!", 9001)

// Function has named returned values

func hello() (message string) {
  message = "Hi there!"

  return
}

greeting := hello()

// Discard return values from a function

func hello() (string, string) {
  return "Hi there!", "Best Friend"
}

greeting, _ := hello()

// Passing pointers into a Go function

func hello(message *string) {
  message = "Howdy!"
}

greeting := "Hi there!"

hello(&greeting)

// The value of greeting is now "Howdy"

// Variadic Functions in Go

func hellos(items ...string) {
  for _, v := range items {
    fmt.Println(v)
  }
}

greetings("Hello", "Bonjour", "Hola")

// Anonymous functions in Go

func () {
  fmt.Println("Hello from an anonymous function")
} ()

Golang Functions In-Depth

Func Main

If you’ve ever written a Go program, even a simple Hello World one, you’ve used functions in Go. The entry way into a Go program is a function called main.

If this is your first experience with Go, then we are about to write our first and required main function. Let’s get to the code.

// Every Go program must have a main package
package main

// The "fmt" library exposes a number of useful methods for displaying content in our terminal window
import "fmt"

// The "main" function is the entry into your Go program
func main(){

  // Print the string "Hello World" to our terminal window
  fmt.Println("Hello World") // "Hello World"

}

The main function executes automatically when you run your Go application.

Every example I show will be a fully functional Go program, so to reinforce your learning and get the most out of this article I suggest you either run it locally or in the Go Playground .

My First Function in Go

The main function can be seen as cheating though. It’s required and we didn’t define when or how it runs. So next let’s write our first “real” function in Go.

As you may have inferred from the main function, the keyword to create a new function is func, followed by the name of the function we want to create.


package main

import "fmt"

// Create the helloWorld function
func helloWorld() {

  // Print the string "Hello World" to our terminal window
  fmt.Println("Hello World")

}

func main() {

  // Call the helloWorld function
  helloWorld()

}

In the above code, we created a function called helloWorld() that took no arguments, did not return any values, and simply just printed the message Hello World to our terminal window. We then called the function from our main() function when the application ran.

By all accounts, this is a pretty basic function, and if all we wanted to do was display text to the console, a whole separate function is likely to be overkill but we’re just getting started.

Return a Value from a Function

We know how to create basic functions that don’t return any values back. Next, let’s create a function that returns some data back to the original function that calls it.


package main

import "fmt"

// Create the helloWorld function
func helloWorld() string {

  // Return the string value "Hello World"
  return "Hello World"

}

func main() {

  // Call the helloWorld function
  message := helloWorld()

  // Print out the value returned from the helloWorld() function
  fmt.Println(message)

}

The helloWorld() function we are creating now returns a string value when it is called. We denote the return value type after the function name and in this case we are telling Go that the helloWorld() function return one value of type string.

In our main() function, we set that return value to a variable called message and then print out the result to the terminal. Since the function now returns a value, we have to store this result somewhere, we can’t just call helloWorld() without assigning it to a variable. Well, that’s not entirely true, but we’ll get to it in a little bit.

Return Multiple Values from a Function

When writing Go functions, you are not limited to a single return value. You are free to return one, two, seventeen, or really any number of values from a function. Let’s see an example of how we can return multiple values from a Go function.


package main

import "fmt"

// Create the helloWorld function
func helloWorld() (string, string) {

  // Return the string value "Hello World"
  return "Hello", "World"

}

func main() {

  // Call the helloWorld function
  hello, world := helloWorld()

  // Print out the values returned from the helloWorld() function
  fmt.Println(hello, world)

}

In this version of the helloWorld() function, we are returning two string values. We are required to wrap our return types in parenthesis when we have more than one return value. In our main() function, we now have two different variables to capture the two values returned. Our Go program would not compile if we called this helloWorld() function and tried to assign the result to just a single variable. The error we’d get would say assignment mismatch: 1 variable but helloWorld returns 2 values.

Return Multiple Values of Different Types from a Function

In the previous example we returned two string values back from our helloWorld() function. In this example, we’ll return three different values all of different types.


package main

import "fmt"

// Create the helloWorld function
func helloWorld() (string, int, bool) {

  // Return the string value "Hello World"
  return "The year is:", 2020, true

}

func main() {

  // Call the helloWorld function
  message, year, current := helloWorld()

  // Print out the values returned from the helloWorld() function if current is true
  if current {
    fmt.Println(message, year)
  }

}

In this helloWorld() function we are returning three values: a string, an integer, and a boolean. In our main() function we also capture these three return types and since we’re using the shorthand := variable notation to create our variables, Go will figure out what types they need to be and correctly assign them.

Passing a Parameter into Go Functions

So far we’ve learned how to create and return data from function in Go. Next, we’ll take a look at how we can pass parameters or arguments into our Go functions. We’ll start with a simple example:


package main

import "fmt"

// Create the helloPlace function
func helloPlace(place string) string {

  // Return the string value "Hello {place}"
  return "Hello " + place

}

func main() {

  city := "Las Vegas"
  // Call the helloPlace function
  city := helloPlace(city)
  state := helloPlace("Nevada")
  country := helloPlace("United States")

  // Print out the value returned from the helloPlace() function
  fmt.Println(city)
  fmt.Println(state)
  fmt.Println(country)

}

The helloPlace() function takes one argument of type string and it returns one value of type string. When we call the helloPlace() function from our main() function, we have to supply it with a string argument or the program will not compile. Since the function also returns a value, we have to capture it’s return.

Passing Multiple Parameters into Go Functions

Passing multiple parameters into a Go function is fairly straightforward as well. Each argument has a name, a type, and is separated by a comma. Let’s see an example:


package main

import "fmt"

// Create the helloPlace function
func helloPlace(greeting string, place string) string {

  // Return the string value "Hello World"
  return greeting + " " + place

}

func main() {

  // Call the helloPlace function
  city := helloPlace("Hello", "Las Vegas")
  state := helloPlace("Bonjour", "Nevada")
  country := helloPlace("Hola", "United States")

  // Print out the value returned from the helloPlace() function
  fmt.Println(city) // "Hello Las Vegas"
  fmt.Println(state) // "Bonjour Nevada"
  fmt.Println(country) // "Hola United States"
}

This version of the helloPlace() function asks for two string values to be passed in, so we’ll have to provide two strings otherwise our code will not compile.

Passing Multiple Parameters of the Same Type into a Go Function

If all of our parameters are of the same type, then we can also just have one type declaration at the end. Feel free to change the helloPlace() function to the following and your code will work all the same:


// Create the helloWorld function
func helloPlace(greeting, place string) string {

  // Return the string value "Hello World"
  return greeting + " " + place

}

This will also work even if you have parameters of different types.


// Create the helloWorld function
func helloPlace(greeting, place string, population int) string {
  if population > 1000000 {
    return greeting + " " + place + " and all your millions of citizens"
  }
  // Return the string value "Hello World"
  return greeting + " " + place

}

In the above case, the greeting and place parameters will be treated as strings, while the population parameter will be treated as an int.

Named Return Values from Functions in Go

In Go, you can also name your return variables. This may seem a bit confusing as the named returned variables are not actually scoped outside of the function. Let’s see an example of how this works and hopefully clear up some of the confusion.


package main

import "fmt"

// Create the helloWorld function
func helloPlace(greeting string, place string) (message string) {

  message = greeting + " " + place
  return
}

func main() {

  // Call the helloPlace function
  city := helloPlace("Hello", "Las Vegas")

  // Print out the value returned from the helloWorld() function
  fmt.Println(city)

}

Our helloPlace() function has a named return value of message. When this function is called, at the top of the helloPlace() scope a new variable called message is created and we can do with it whatever we want. In our example, we’re concatenating and assigning the parameters we receive from the main() function to the message variable.

Our return statement is also blank. This is referred to as a naked return. Since we have a named return parameter, our Go program will return the value of message without us having to explicitly return it. We still have to call return, but we don’t have to give it anything to return, it will by default return whatever the value of message is. We can overwrite this though, if we did happen to give the return statement a string value to return, it would and the message value would be overwritten.

Discarding Values from Go Functions

We’ve spent a lot of time talking about different ways to return values from Go functions. Most of the type, you’re going to want to do something with the return value or values, but there may be instances where you don’t care about what’s returned. Let’s go back to an earlier program we wrote and discard some of the values we get back.


package main

import "fmt"

// Create the helloWorld function
func helloWorld() (string, int, bool) {

  // Return the string value "Hello World"
  return "The year is:", 2020, true

}

func main() {

  // Call the helloWorld function
  message, _, _ := helloWorld()

  // Print out the values of message
  fmt.Println(message)

}

Our helloWorld() function hasn’t changed, so when it’s called it will return three different values to the function that called it. But in our case, we only care about the result of the first value. To discard the second and third, instead of giving it a named variable, we use and underscore (_). This will tell Go that we understand this function is returning a value, but to discard it because we don’t plan to do anything with it.

You can discard any return value regardless of it’s location in the function signature, but if the function is returning multiple values there’s probably a good reason for it and you should make an effort to use all of the returned values.

Passing Pointers into Go Functions

All the functions we’ve written up to this point that have accepted parameters have accepted the arguments by value. What this means is that when we call helloPlace() and pass in “Hello” as the string, or if we had a variable called message that held the value “Hello”, when the data is passed into the Go function, it’s a copy and not the original value.

Let’s make a few adjustments to our function signature, and for the greeting we’ll keep it the same, but for the place variable, instead of accepting the parameter by value, we’ll accept a pointer to an existing variable. Also, we won’t return anything from the function, we’ll just reassign the values we receive and print the new values out in the main() function. Let’s see how this will change our code.


package main

import "fmt"

// Create the helloPlace function
func helloPlace(greeting string, place *string) {

  greeting = "Bonjour"
  place = "United States"

}

func main() {

  message := "Hello"
  location := "Las Vegas"

  // Call the helloPlace function
  helloPlace(message, &location)

  // Print out the values of message and location
  fmt.Println(message) // "Hello"
  fmt.Println(location) // "United States"

}

We defined two variables message and location. We then called the helloPlace() function passing in the message variable and a pointer to the location variable. Inside of the helloPlace() function we reassigned the values of both of the messages, and then in our main() function printed the values of message and location. Note that while the message variable did not change from its original string “Hello”, the location string did change to United States.

The reason for this is that we passed the location variable by reference and not by value, so rather than passing in a copy of the contents of the location variable, we gave the helloPlace() function the memory location of it instead.

Variadic Functions in Go

To wrap up this article, we’ll take a look at how we can create variadic functions in Go. A variadic function is a function that takes any number of arguments.

The syntax for a variadic function in Go looks like this:

package main

import "fmt"

func greetings(items ...string) {
  for _, v := range items {
    fmt.Println(v)
  }
}

func main(){
  greetings("Hello", "Bonjour", "Hola")
}

The greetings() function will now take any number of string arguments. In our example above, we’re ranging over the list and printing each one out on its own line. The items variable gets converted into a slice. But what if we wanted to pass a slice into a variadic function?

package main

import "fmt"

func greetings(items ...string) {
  for _, v := range items {
    fmt.Println(v)
  }
}

func main(){
  hellos := []string{"Hello", "Bonjour", "Hola"}

  greetings(hellos...)
}

If you have an existing slice or array that you want to pass into a variadic function, you can easily use it as an argument, but you will need to append ... to the end of it. If you just passed in hellos without the ..., you would get an error.

Any function can be a variadic function, the only requirement is that the variadic arguments come last.

package main

import "fmt"

func greetings(country string, code int, items ...string) {
  fmt.Println(country)
  fmt.Println(code)
  for _, v := range items {
    fmt.Println(v)
  }
}

func main(){
  hellos := []string{"Hello", "Bonjour", "Hola"}

  greetings("United States", 1, hellos...)
}

In our updated greetings() function we accept two static parameters, and then the variadic ones. So to cal our greetings() function we have to pass in a country and code parameter, but the items are optional. We can pass 0, 1, or n number of string arguments.

Anonymous Functions in Go

Go allows you to create anonymous functions. An anonymous function is a function that does not have a named identifier. There are a couple of different ways we can work with anonymous functions and they have legitimate uses.

package main

import "fmt"

func main(){
  func () {
    fmt.Println("Hello from an anonymous function")
  } ()
}

In the above program, when our main() function is called, we automatically call an anonymous function which prints the message "Hello from an anonymous function". Note that with the anonymous function, we don’t give it a name, and we pass a parenthesis after the function to call it. If we wanted to pass arguments into the anonymous function we could add them in those parenthesis like so:

package main

import "fmt"

func main(){
  func (message string) {
    fmt.Println(message)
  } ("Hello from an anonymous function")
}

Just like with regular functions, our anonymous functions can return values.

package main

import "fmt"

func main(){
  content := func (message string) string {
    return message
  } ("Hello from an anonymous function")

  fmt.Println(content)
}

And finally, an anonymous function can also be assigned to a variable and reused. Although, if you’re using it in this way, you might as well create a proper function.

package main

import "fmt"

func main(){

  var message = func (message string) string {
    return message
  }

  content := message("Hello from an anonymous function")

  fmt.Println(content)
}

Putting It All Together

We covered a lot of functions today and we’re just scratching the surface of what’s possible. Functions in Go are very powerful and give us a lot of flexibility on how we want to approach problem-solving. I hope you found this cheatsheet helpful and if you have any questions, please feel free to reach out.

See Also