Functions in Go

Learn to write functions in Go: parameters and typed returns, multiple and named return values, variadic functions, closures, and the result-error convention.

Prerequisites

Learning objectives

  • Declare functions with typed parameters and return values
  • Return multiple values and follow the result-error convention
  • Use variadic functions and closures where they fit

A function groups reusable logic behind a name. You declare one with the func keyword, list its typed parameters, and state the types it returns. Functions are the main unit of reuse in Go, and they are values too.

Declaring a function

The parameter list comes first, then the return type, then the body. Use return to send a value back.

func greet(name string) string {
	return "Hello, " + name
}

When several parameters share a type, you can write the type once at the end:

func add(a, b int) int {
	return a + b
}

Multiple return values

Go functions can return more than one value. This is used constantly, most often to return a result alongside a status.

func minMax(a, b int) (int, int) {
	if a < b {
		return a, b
	}
	return b, a
}

The caller receives both values with a single call: lo, hi := minMax(9, 4).

Named returns (use sparingly)

You can name the return values. They act like variables initialised to their zero value, and a bare return sends their current values back.

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}

Named returns can document intent, but a bare return in a long function is easy to misread. Prefer explicit returns unless the names genuinely add clarity.

Variadic functions

A final parameter written ...T accepts any number of arguments, which arrive as a slice.

func sum(nums ...int) int {
	total := 0
	for _, n := range nums {
		total += n
	}
	return total
}

Call it as sum(1, 2, 3), or spread an existing slice with sum(values...).

Functions as values and closures

Functions are first-class values: you can store them in variables and return them. A function that captures variables from its surrounding scope is a closure.

func counter() func() int {
	count := 0
	return func() int {
		count++
		return count
	}
}

Each call to counter() returns a fresh function with its own private count.

The result-error convention

Idiomatic Go reports failure by returning a value and an error. By convention the error is the last return value, and it is nil on success. The caller checks it before using the result.

package main

import (
	"errors"
	"fmt"
)

// divide returns the integer quotient of a by b.
// It returns an error when b is zero.
func divide(a, b int) (int, error) {
	if b == 0 {
		return 0, errors.New("division by zero")
	}
	return a / b, nil
}

func main() {
	if q, err := divide(10, 2); err == nil {
		fmt.Println("10 / 2 =", q)
	}

	if _, err := divide(1, 0); err != nil {
		fmt.Println("error:", err)
	}
}

Running it prints:

10 / 2 = 5
error: division by zero

Common mistakes

  • Ignoring the returned error. If a function returns (T, error), check the error; do not discard it with _ unless you are certain it cannot occur.
  • Returning a useful value alongside a non-nil error. On failure, return the zero value so callers are not tempted to use garbage.
  • Overusing named returns. In long functions a bare return hides what is actually sent back. Name returns only when it improves clarity.

Practice

Write a function average(nums ...float64) float64 that returns the mean of its arguments, and 0 when called with none. Print the average of 4, 8, 15, 16, 23, 42 with two decimals.

Show the solution
package main

import "fmt"

func average(nums ...float64) float64 {
	if len(nums) == 0 {
		return 0
	}
	var sum float64
	for _, n := range nums {
		sum += n
	}
	return sum / float64(len(nums))
}

func main() {
	fmt.Printf("%.2f\n", average(4, 8, 15, 16, 23, 42))
}

Guarding against the empty case avoids a division by zero, and dividing the sum by the count gives 18.00.

Summary

  • Declare functions with func, typed parameters, and typed returns.
  • Multiple return values power the (result, error) convention.
  • Variadic parameters and closures make functions flexible; keep them small.

Next, dig into the idiom that shapes Go APIs with error handling, and revisit how values are stored in variables and types.

Your progress is stored only in this browser. No account is required.

Search

Search runs entirely in your browser.