Multiple return values in Golang functions

A function in Go can return multiple values. In many cases, it is very useful. Multiple return values help to check errors in a concise way as we will see in this post.

Golang Function return values

A function can have any number of return values. Go supports this feature internally. Let’s see how a function can return multiple values. The syntax of the multi-return function is shown below:

func funcName(p1 paramType1, p2 paramType2, ...) (returnType1, returnType2, ..., returnTypeN) {}

Declaration of return types

The return types and values can be declared in multiple ways as we will see. When we are returning multiple-type of the value we can declare it like this.

package main

import (
	"fmt"
)

func doubleIt(p int) (int) {
	return p * 2
}

func main() {
	fmt.Println(doubleIt(9))  // prints 18
}

Declaration of the same return types

If we use same-typed return values then we can declare it like this to shorten our code like this.

package main

import (
	"fmt"
)

func f(v int) (int, int) {
	return v/2, v*2
}

func main() {
	x, y := f(12)
	
	fmt.Println(x, y)  // 6 24
}

Declaration of the different return types

If we use different-typed return values then we can declare it like this shown below.

package main

import (
	"fmt"
)

func f(v int) (int, float64) {
	return v/2, float64(v)*2.05
}

func main() {
	x, y := f(12)
	
	fmt.Println(x, y)  // 6 24.599999999999998
}

Named return types

Named return types are a feature in Go where you can define the names of the return values. The benefit of using the named return types is that it allows us to not explicitly return each one of the values.

Thus makes it very helpful for complicated calculations where multiple values are calculated in many different steps.

Here is an example showing named return types in action.

package main

import (
	"fmt"
)

func g(v int) (x, y int) {
	x = v+4
	y = v-4
	return        // notice that we are not returning any value
}

func main() {
	x, y := g(12)
	
	fmt.Println(x, y)  // 16 8
}

Benefits of multiple return values

Multiple return values are extremely useful when checking errors as you will see. It makes the program flow easier since you are checking the errors in a step-by-step manner. Thus omits the need for complicated and nested error-checking and other problems.

Multiple return values return each of them separately so it reduces the needs of unpacking data from a packed structure. It also reduces the needs of returning pointers to data.

Skipping a return value

Any number of return values can be ignored completely. Go has a literal, the hyphen (-) which can be used in place of the data and the data will be skipped completely. Here we can see how to skip return values.

package main

import (
	"fmt"
)

func h(v int) (int, int) {
	return v*2, v*4
}

func main() {
	x, _ := h(23)   // obeserve the skip operator is used to ignore
	                // the compiler doesn't throw error this time
	
	fmt.Println(x)  // 46
}

Needs for skipping return values

Go has a feature where if you initialize a variable but do not use it, Go compiler will give errors. The error will be very annoying if you store all return values in variables but do not use it.

This problem can be entirely avoided by skipping the variables. Here is an example showing just that.

Error handling with multiple return values

Go has excellent error handling support for multiple return values. We simply can return an error when doing any operation. Then check the errors sequentially as shown below.

package main

import (
	"fmt"
	"errors"
)

func f(v int) (int, error) {
	if v == 0 {
		return 0, errors.New("Zero not allowed")
	} else {
		return v * 2, nil
	}
}

func main() {
	v, e := f(0)
	if e != nil {  // check error here
		fmt.Println("Error!!!")
	} else {
		fmt.Println(v)
	}
	
	// output:
	// Error!!!
}