Go > Core Go Basics > Functions > Multiple return values
Returning Multiple Values in Go Functions
Go functions can return multiple values, offering a clean and efficient way to handle errors or return related data. This approach avoids the need for complex struct definitions when multiple return values are appropriate.
Basic Example: Dividing with Error Handling
This example demonstrates a simple division function that returns both the result and an error. If the divisor is zero, an error is returned. Otherwise, the result and a nil error are returned. The `errors.New()` function is used to create a new error instance with a descriptive message. In the `main` function, we check for the error before using the result.
package main
import (
"fmt"
"errors"
)
// divide function returns both the result and an error, if any.
func divide(dividend, divisor float64) (float64, error) {
if divisor == 0 {
return 0, errors.New("division by zero")
}
return dividend / divisor, nil
}
func main() {
res, err := divide(10.0, 2.0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", res)
res, err = divide(5.0, 0.0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", res)
}
Concepts Behind Multiple Return Values
Go's ability to return multiple values is a key feature for error handling and conveying related data points from a function. Instead of relying on exceptions (which Go doesn't have) or complex struct return types for simple scenarios, multiple return values provide a concise and readable approach. The last value returned is often an error type, allowing functions to gracefully handle and communicate failure conditions.
Real-Life Use Case: Reading Data with Status
Consider a scenario where you're fetching data from a database or an API. The function needs to return the data itself and also indicate whether the fetch was successful. Multiple return values (data, success) are a perfect fit here. The code example illustrates a `fetchData` function that returns a string and a boolean indicating success or failure.
package main
import (
"fmt"
)
// fetchData simulates fetching data. Returns data and a boolean indicating success.
func fetchData(id int) (string, bool) {
if id < 0 {
return "", false // Indicate failure
}
data := fmt.Sprintf("Data for ID %d", id)
return data, true // Indicate success
}
func main() {
data, ok := fetchData(123)
if ok {
fmt.Println("Data:", data)
} else {
fmt.Println("Failed to fetch data.")
}
data, ok = fetchData(-1)
if ok {
fmt.Println("Data:", data)
} else {
fmt.Println("Failed to fetch data.")
}
}
Best Practices
Interview Tip
Be prepared to explain how Go handles errors (through multiple return values), why it's preferred over exceptions, and how it promotes explicit error handling. Also, be ready to demonstrate how to write a function with multiple return values and how to handle them in the calling code.
When to Use Them
Use multiple return values when you need to return related data or signal success/failure along with a result. They are particularly useful for error handling, returning status codes, or providing ancillary information along with the primary result of a function.
Alternatives
Alternatives to multiple return values include:
Pros
Cons
FAQ
-
Can I ignore a return value?
Yes, you can ignore a return value using the blank identifier `_`. For example: `_, err := someFunction()`. However, ignoring the error return value is generally discouraged, as it can lead to unexpected behavior. -
What happens if a function doesn't return all the values it declares?
Go will return the zero value for any missing return values. For example, if a function declares `(int, error)` but only explicitly returns an `error`, the `int` will be zero.