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.