How To Define and Call Functions in Go

Written by Gopher Guides

A function is a section of code that, once defined, can be reused. Functions are used to make your code easier to understand by breaking it into small, understandable tasks that can be used more than once throughout your program.

Go ships with a powerful standard library that has many predefined functions. Ones that you are probably already familiar with from the fmt package are:

  • fmt.Println() which will print objects to standard out (most likely your terminal).
  • fmt.Printf() which will allow you to format your printed output.

Function names include parentheses and may include parameters.

In this tutorial, we’ll go over how to define your own functions to use in your coding projects.

Defining a Function

Let’s start with turning the classic “Hello, World!” program into a function.

We’ll create a new text file in our text editor of choice, and call the program hello.go. Then, we’ll define the function.

A function is defined by using the func keyword. This is then followed by a name of your choosing and a set of parentheses that hold any parameters the function will take (they can be empty). The lines of function code are enclosed in curly brackets {}.

In this case, we’ll define a function named hello():

hello.go

  1. func hello() {}

This sets up the initial statement for creating a function.

From here, we’ll add a second line to provide the instructions for what the function does. In this case, we’ll be printing Hello, World! to the console:

hello.go

  1. func hello() {
  2. fmt.Println("Hello, World!")
  3. }

Our function is now fully defined, but if we run the program at this point, nothing will happen since we didn’t call the function.

So, inside of our main() function block, let’s call the function with hello():

hello.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. hello()
  5. }
  6. func hello() {
  7. fmt.Println("Hello, World!")
  8. }

Now, let’s run the program:

  1. go run hello.go

You’ll receive the following output:

Output

  1. Hello, World!

Notice that we also introduced a function called main(). The main() function is a special function that tells the compiler that this is where the program should start. For any program that you want to be executable (a program that can be run from the command line), you will need a main() function. The main() function must appear only once, be in the main() package, and receive and return no arguments. This allows for program execution in any Go program. As per the following example:

main.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("this is the main section of the program")
  5. }

Functions can be more complicated than the hello() function we defined. We can use for loops, conditional statements, and more within our function block.

For example, the following function uses a conditional statement to check if the input for the name variable contains a vowel, then uses a for loop to iterate over the letters in the name string.

names.go

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. func main() {
  7. names()
  8. }
  9. func names() {
  10. fmt.Println("Enter your name:")
  11. var name string
  12. fmt.Scanln(&name)
  13. // Check whether name has a vowel
  14. for _, v := range strings.ToLower(name) {
  15. if v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u' {
  16. fmt.Println("Your name contains a vowel.")
  17. return
  18. }
  19. }
  20. fmt.Println("Your name does not contain a vowel.")
  21. }

The names() function we define here sets up a name variable with input, and then sets up a conditional statement within a for loop. This shows how code can be organized within a function definition. However, depending on what we intend with our program and how we want to set up our code, we may want to define the conditional statement and the for loop as two separate functions.

Defining functions within a program makes our code modular and reusable so that we can call the same functions without rewriting them.

Working with Parameters

So far we have looked at functions with empty parentheses that do not take arguments, but we can define parameters in function definitions within their parentheses.

A parameter is a named entity in a function definition, specifying an argument that the function can accept. In Go, you must specify the data type for each parameter.

Let’s create a program that repeats a word a specified number of times. It will take a string parameter called word and an int parameter called reps for the number of times to repeat the word.

repeat.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. repeat("Sammy", 5)
  5. }
  6. func repeat(word string, reps int) {
  7. for i := 0; i < reps; i++ {
  8. fmt.Print(word)
  9. }
  10. }

We passed the value Sammy in for the word parameter, and 5 for the reps parameter. These values correspond with each parameter in the order they were given. The repeat function has a for loop that will iterate the number of times specified by the reps parameter. For each iteration, the value of the word parameter is printed.

Here is the output of the program:

Output

  1. SammySammySammySammySammy

If you have a set of parameters that are all the same value, you can omit specifying the type each time. Let’s create a small program that takes in parameters x, y, and z that are all int values. We’ll create a function that adds the parameters together in different configurations. The sums of these will be printed by the function. Then we’ll call the function and pass numbers into the function.

add_numbers.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. addNumbers(1, 2, 3)
  5. }
  6. func addNumbers(x, y, z int) {
  7. a := x + y
  8. b := x + z
  9. c := y + z
  10. fmt.Println(a, b, c)
  11. }

When we created the function signature for addNumbers, we did not need to specify the type each time, but only at the end.

We passed the number 1 in for the x parameter, 2 in for the y parameter, and 3 in for the z parameter. These values correspond with each parameter in the order they are given.

The program is doing the following math based on the values we passed to the parameters:

  1. a = 1 + 2
  2. b = 1 + 3
  3. c = 2 + 3

The function also prints a, b, and c, and based on this math we would expect a to be equal to 3, b to be 4, and c to be 5. Let’s run the program:

  1. go run add_numbers.go

Output

  1. 3 4 5

When we pass 1, 2, and 3 as parameters to the addNumbers() function, we receive the expected output.

Parameters are arguments that are typically defined as variables within function definitions. They can be assigned values when you run the method, passing the arguments into the function.

Returning a Value

You can pass a parameter value into a function, and a function can also produce a value.

A function can produce a value with the return statement, which will exit a function and optionally pass an expression back to the caller. The return data type must be specified as well.

So far, we have used the fmt.Println() statement instead of the return statement in our functions. Let’s create a program that instead of printing will return a variable.

In a new text file called double.go, we’ll create a program that doubles the parameter x and returns the variable y. We issue a call to print the result variable, which is formed by running the double() function with 3 passed into it:

double.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. result := double(3)
  5. fmt.Println(result)
  6. }
  7. func double(x int) int {
  8. y := x * 2
  9. return y
  10. }

We can run the program and see the output:

  1. go run double.go

Output

  1. 6

The integer 6 is returned as output, which is what we would expect by multiplying 3 by 2.

If a function specifies a return, you must provide a return as part of the code. If you do not, you will receive a compilation error.

We can demonstrate this by commenting out the line with the return statement:

double.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. result := double(3)
  5. fmt.Println(result)
  6. }
  7. func double(x int) int {
  8. y := x * 2
  9. // return y
  10. }

Now, let’s run the program again:

  1. go run double.go

Output

  1. ./double.go:13:1: missing return at end of function

Without using the return statement here, the program cannot compile.

Functions exit immediately when they hit a return statement, even if they are not at the end of the function:

return_loop.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. loopFive()
  5. }
  6. func loopFive() {
  7. for i := 0; i < 25; i++ {
  8. fmt.Print(i)
  9. if i == 5 {
  10. // Stop function at i == 5
  11. return
  12. }
  13. }
  14. fmt.Println("This line will not execute.")
  15. }

Here we iterate through a for loop, and tell the loop to run 25 iterations. However, inside the for loop, we have a conditional if statement that checks to see if the value of i is equal to 5. If it is, we issue a return statement. Because we are in the loopFive function, any return at any point in the function will exit the function. As a result, we never get to the last line in this function to print the statement This line will not execute..

Using the return statement within the for loop ends the function, so the line that is outside of the loop will not run. If, instead, we had used a break statement, only the loop would have exited at that time, and the last fmt.Println() line would run.

The return statement exits a function, and may return a value if specified in the function signature.

Returning Multiple Values

More than one return value can be specified for a function. Let’s examine the repeat.go program and make it return two values. The first will be the repeated value and the second will be an error if the reps parameter is not a value greater than 0:

repeat.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. val, err := repeat("Sammy", -1)
  5. if err != nil {
  6. fmt.Println(err)
  7. return
  8. }
  9. fmt.Println(val)
  10. }
  11. func repeat(word string, reps int) (string, error) {
  12. if reps <= 0 {
  13. return "", fmt.Errorf("invalid value of %d provided for reps. value must be greater than 0.", reps)
  14. }
  15. var value string
  16. for i := 0; i < reps; i++ {
  17. value = value + word
  18. }
  19. return value, nil
  20. }

The first thing the repeat function does is check to see if the reps argument is a valid value. Any value that is not greater than 0 will cause an error. Since we passed in the value of -1, this branch of code will execute. Notice that when we return from the function, we have to provide both the string and error return values. Because the provided arguments resulted in an error, we will pass back a blank string for the first return value, and the error for the second return value.

In the main() function, we can receive both return values by declaring two new variables, value and err. Because there could be an error in the return, we want to check to see if we received an error before continuing on with our program. In this example, we did receive an error. We print out the error and return out of the main() function to exit the program.

If there was not an error, we would print out the return value of the function.

Note: It is considered best practice to only return two or three values. Additionally, you should always return all errors as the last return value from a function.

Running the program will result in the following output:

Output

  1. invalid value of -1 provided for reps. value must be greater than 0.

In this section we reviewed how we can use the return statement to return multiple values from a function.

Conclusion

Functions are code blocks of instructions that perform actions within a program, helping to make our code reusable and modular.

To learn more about how to make your code more modular, you can read our guide on How To Write Packages in Go.