Go Functions

Functions in Go bundle reusable logic behind a name, and Go's support for multiple return values makes them especially good at reporting both a result and an error.

Declaring a function

A function declaration starts with the func keyword, followed by a name, a parenthesized parameter list, an optional return type, and a body in braces. Each parameter must state its type, though consecutive parameters that share a type can list the type once at the end of the group.

A simple function with parameters

package main

import "fmt"

func greet(name string, times int) {
	for i := 0; i < times; i++ {
		fmt.Println("Hello,", name)
	}
}

func main() {
	greet("Maria", 2)
}

Returning a value

To send a result back to the caller, a function declares a return type after its parameter list and uses the return keyword in its body. The returned value's type must match the declared return type exactly, since Go performs no implicit conversion between numeric types.

Function with a return value

package main

import "fmt"

func square(n int) int {
	return n * n
}

func main() {
	result := square(6)
	fmt.Println("Result:", result)
}

Multiple return values

Go functions can return more than one value, which is written as a comma-separated list of types in parentheses. This feature is used throughout the standard library to return a result alongside an error, avoiding the need for exceptions or out-parameters.

Multiple return values for a result and an error

package main

import (
	"errors"
	"fmt"
)

func divide(a, b float64) (float64, error) {
	if b == 0 {
		return 0, errors.New("cannot divide by zero")
	}
	return a / b, nil
}

func main() {
	result, err := divide(10, 2)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Result:", result)
}

Named return values

Return values can be given names in the function signature, which pre-declares them as variables initialized to their zero value. A bare return statement then sends back whatever those named variables currently hold. Named returns can make short functions more self-documenting, but in longer functions they are best avoided since the values can be easy to lose track of.

  • Parameters are always passed by value in Go — the function receives a copy, so reassigning a parameter inside the function does not affect the caller's variable.
  • Slices, maps, and pointers still copy the value itself, but that value contains a reference to the same underlying data, so mutating their contents is visible to the caller.
  • A function with no return type simply omits it after the parameter list.
  • Variadic parameters, written as ...T, let a function accept a variable number of trailing arguments of type T.
Return styleExample signatureWhen to use
Single valuefunc square(n int) intOne clear result
Multiple valuesfunc divide(a, b float64) (float64, error)Result plus an error or status
Named returnsfunc split(sum int) (x, y int)Short functions where names add clarity
Note: By convention, when a function returns an error, it should be the last return value, and callers should check it before trusting the other values.
Note: The Go compiler rejects unused local variables but not unused function parameters — so an unused parameter will not stop your program from compiling, though linters will often flag it.

Exercise: Go Functions

Can a Go function return more than one value?