Go Gopher How to Go

Multiple Return Values

Go has built-in support for multiple return values. This feature is used extensively in idiomatic Go, especially for returning both a result and an error value from a function.

💡 Key Points

  • Go supports returning multiple values from a single function
  • The (result, error) pattern is idiomatic for error handling
  • Use blank identifier _ to ignore return values you don't need
  • Named return values are initialized to zero values and can be modified before return
  • Naked returns (return without arguments) use named return values
  • Map lookups use (value, ok) pattern where ok indicates if key exists
  • Type assertions use (value, ok) pattern for safe type conversion
  • All return values must be handled or explicitly discarded

Basic Multiple Returns

A function can return multiple values by specifying them in parentheses:

package main

import "fmt"

// Function returns two integers
func vals() (int, int) {
    return 3, 7
}

func main() {
    // Get both return values
    a, b := vals()
    fmt.Println("vals:", a, b)
    
    // Use only one return value, discard the other
    _, c := vals()
    fmt.Println("only second:", c)
}
Output:
vals: 3 7
only second: 7

Multiple Returns with Error Handling

The most common use of multiple returns is for error handling, where functions return a value and an error:

package main

import (
    "fmt"
    "errors"
)

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

func main() {
    // Successful operation
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("10 / 2 =", result)
    }
    
    // Error case
    result, err = divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result)
    }
}
Output:
10 / 2 = 5
Error: cannot divide by zero

Multiple Return Patterns

PatternExampleUse Case
(T, error)func read() ([]byte, error)Most common: return value and error
(T, bool)func lookup() (string, bool)Return value and success indicator
(T1, T2)func split() (int, int)Return multiple related values
(T1, T2, error)func parse() (int, string, error)Multiple values with error
(x, y T)func coords() (x, y int)Named return values

Named Return Values

FeatureDescriptionExample
DeclarationName return values in function signaturefunc split() (x, y int)
InitializationNamed returns are initialized to zero valuesx and y start as 0
Naked returnReturn without arguments returns named valuesreturn // returns x, y
DocumentationMakes return values self-documentingfunc div() (quotient, remainder int)
Deferred functionsCan modify return values in deferdefer func() { x++ }()

Best Practices

PracticeRecommendationReason
Error as last returnAlways return error as the last valueIdiomatic Go convention
Blank identifierUse _ to ignore unwanted returnsExplicitly shows intention to discard value
Naked returnsUse sparingly, only in short functionsCan reduce readability in longer functions
Boolean vs ErrorUse bool for existence, error for failuresMap lookups use bool; I/O operations use error
Return countLimit to 2-3 returns when possibleToo many returns can indicate need for struct