Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 6

Functions: Parameters and Return Values

Recommended resources

Welcome to your next lesson! In our previous session, we dove into loops and saw how to make your Go programs repeat actions using the versatile for keyword. You even put this into practice by implementing the fibonacci function. You may have noticed we created and used that function without much formal discussion about what a function really is.

In this lesson, we'll fix that. We are going to build a solid understanding of functions, the fundamental building blocks of any well-structured program. For a backend developer, mastering functions is non-negotiable; they are how you create modular, reusable, and testable code. We will cover how to define and call functions, how to pass data into them using typed parameters, and how to get data out using one of Go's most distinctive features: multiple return values.

1. The Anatomy of a Go Function

A function is a self-contained block of code that performs a specific task. If you have a background in Python, you're already familiar with the concept of defining a function with def. In Go, the idea is the same, but the syntax is different. Functions help us break down large, complex problems into smaller, manageable pieces.

Let's begin by examining the basic syntax for declaring functions in Go, including how to define parameters and specify what type of data the function will return.

Learn Functions in Go with Examples | golangbot.com

This article from golangbot.com provides a clear and structured introduction to Go functions.

Please read the first two sections, "What is a function?" and "Sample Function". Pay close attention to the func keyword, the placement of parameter names and types, and the declaration of the return type. Notice the shorthand price, quantity int for parameters of the same type.

The reading gives a solid, textual foundation. Now, let's watch a video that walks through these same concepts, showing you how to define, call, and return values from functions in a live-coding context.

Go (Golang) Tutorial #9 - Using Functions

This video from Net Ninja provides a great visual demonstration of creating and using functions.

Please watch the segments covering the basics of functions and returning values. First, watch the introduction and the creation of a basic function with parameters from the beginning. Then, jump to the section on returning values from a function, which demonstrates the circleArea example from this timestamp.


2. Multiple Return Values: A Go Superpower

One of Go's most idiomatic and powerful features is the ability for a function to return multiple values directly. In many other languages, you'd need to return a special object or a collection like a tuple to achieve this. Go makes it a clean, first-class part of the language. This is extremely common in Go code, especially for returning a result alongside an error status, a pattern we will see time and time again.

The following video provides an excellent, step-by-step explanation of how to define a function that returns multiple values and how to receive those values when you call the function.

Golang Tutorial #16 - Functions

In this clip, Tech With Tim clearly demonstrates the syntax for multiple return values.

Watch the section from this point. Notice how the return types are grouped in parentheses (int, int) and how two variables are used on the left side of the := operator to capture both returned values.

Let's look at another practical example. The code snippet below shows an average function that calculates two things and returns both: the average value and the count of numbers processed.

A Go function named `average` demonstrates multiple returns. It returns two `int` values, which are then assigned to the `avg` and `n` variables in a single statement in the `main` function.

In the main function, the line avg, n = average(2, 10, 6) is where the magic happens. The average function executes and returns two integers. The first is assigned to avg, and the second is assigned to n. (Note: The series ...int part is a variadic parameter, a topic we'll cover in a future module. For now, focus on the (int, int) return signature.)


3. Handling Multiple Returns: The Blank Identifier _

What if a function returns two values, but you only care about one of them? For example, what if you only wanted the area from a function that returns both area and perimeter?

Go's compiler is strict: it will produce an error if you declare a variable but never use it. This helps keep code clean and bug-free. To handle this, Go provides the blank identifier, an underscore _. When you assign a value to _, you are telling the compiler that you are intentionally discarding this value.

Let's read the short section that explains this essential tool.

Learn Functions in Go with Examples | golangbot.com

This section of the golangbot.com article shows a practical example of using the blank identifier.

Read the section titled Blank Identifier. Focus on the line area, _ := rectProps(10.8, 5.6) and understand why the underscore is necessary here.

To cement these ideas, and to honor your goal of mastering everything on "Go by Example," let's use it as a reference. This resource provides concise, runnable examples for core language features.

Go by Example

"Go by Example" is a crucial resource for any Go developer. We will refer to it often.

Please visit the main page. In the list of topics, find and click on Functions to review the syntax. Afterwards, click on Multiple Return Values to see another clear example of this pattern.


4. Practice: Finding the Min and Max

It's time to put these concepts into practice with a small algorithmic challenge. Your task is to write a function that takes a slice of integers and finds both the smallest and largest numbers in that slice in a single pass. This is a perfect use case for multiple return values.

Instructions:

  1. Create a new file named functions.go.
  2. Copy the code skeleton below into your file.
  3. Implement the logic inside the findMinMax function.
    • Handle the edge case of an empty slice.
    • Initialize min and max with the first element of the slice.
    • Use a for loop (like we learned in the last lesson!) to iterate through the rest of the slice.
    • Inside the loop, update min and max if you find a smaller or larger number.
    • Return both min and max.
  4. Run your code with go run functions.go and verify the output.

Code Skeleton:

package main

import "fmt"

// findMinMax takes a slice of integers and returns the minimum and maximum values.
// If the slice is empty, it should return 0 for both min and max.
func findMinMax(numbers []int) (int, int) {
	// TODO: Handle the case where the numbers slice is empty.
	// If it is, return 0, 0.
	if len(numbers) == 0 {
		return 0, 0
	}

	// TODO: Initialize min and max to the first element of the slice.
	min := numbers[0]
	max := numbers[0]

	// TODO: Use a for loop to iterate through the rest of the numbers (starting from the second element).
	// The `range` keyword is great for this.
	// Inside the loop, update min and max if a smaller or larger number is found.
	for _, number := range numbers[1:] {
		if number < min {
			min = number
		}
		if number > max {
			max = number
		}
	}

	// TODO: Return the final min and max values.
	return min, max
}

func main() {
	nums := []int{4, 9, 2, 10, -1, 5, 8}
	min, max := findMinMax(nums)
	fmt.Printf("For the numbers %v:\n", nums)
	fmt.Printf("The minimum is: %d\n", min)
	fmt.Printf("The maximum is: %d\n", max)

	emptySlice := []int{}
	minEmpty, maxEmpty := findMinMax(emptySlice)
	fmt.Printf("\nFor an empty slice:\n")
	fmt.Printf("The minimum is: %d\n", minEmpty)
	fmt.Printf("The maximum is: %d\n", maxEmpty)
}

Expected Output:

For the numbers [4 9 2 10 -1 5 8]:
The minimum is: -1
The maximum is: 10

For an empty slice:
The minimum is: 0
The maximum is: 0

Conclusion

In this lesson, you've taken a significant step toward writing clean and effective Go code. You now have the tools to encapsulate logic into reusable units, a cornerstone of professional software development.

Key Takeaways:

  • Function Syntax: You declare functions with the func keyword, followed by the function name, typed parameters, an optional return type, and the function body in curly braces.
  • Multiple Returns: Go functions can return multiple values, a feature that promotes clean and clear code, especially for returning a result and an error.
  • The Blank Identifier (_): You can use the underscore to explicitly ignore function return values you don't need, satisfying the compiler's "no unused variables" rule.
  • Modularity: Functions allow you to break your program into logical, self-contained pieces, making your code easier to read, debug, and maintain.

So far, we've been using fmt.Println and fmt.Printf to see the output of our programs. In the next lesson, we will take a more systematic look at the fmt package, exploring more advanced ways to format strings and control the output to your console. This will give you fine-grained control over how your backend services communicate information.