Multiple Return Values in Go
Multiple return values are a distinctive feature of Go. They enable elegant error handling and returning multiple results without using pointers or structs.
Basic Multiple Returns
Returning Two Values
package main
import "fmt"
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Returning Multiple Values
package main
import "fmt"
func getCoordinates() (float64, float64, string) {
return 10.5, 20.3, "Point A"
}
func main() {
x, y, label := getCoordinates()
fmt.Printf("Point %s: (%.1f, %.1f)\n", label, x, y)
}
Named Return Values
Using Named Returns
package main
import "fmt"
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = fmt.Errorf("division by zero")
return
}
result = a / b
return
}
func main() {
result, err := divide(10, 2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Named Returns with Documentation
package main
import "fmt"
// Calculate returns the sum and product of two numbers
func calculate(a, b int) (sum int, product int) {
sum = a + b
product = a * b
return
}
func main() {
s, p := calculate(5, 3)
fmt.Printf("Sum: %d, Product: %d\n", s, p)
}
Error Handling Patterns
The Error Pattern
package main
import (
"fmt"
"os"
)
func readFile(filename string) ([]byte, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
return data, nil
}
func main() {
data, err := readFile("data.txt")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Data:", string(data))
}
Multiple Error Returns
package main
import (
"fmt"
"strconv"
)
func parseInts(strs []string) ([]int, error) {
result := make([]int, len(strs))
for i, s := range strs {
num, err := strconv.Atoi(s)
if err != nil {
return nil, fmt.Errorf("invalid number at index %d: %w", i, err)
}
result[i] = num
}
return result, nil
}
func main() {
nums, err := parseInts([]string{"1", "2", "3"})
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Numbers:", nums)
}
}
Ignoring Return Values
Using Blank Identifier
package main
import (
"fmt"
"os"
)
func main() {
// Ignore error
data, _ := os.ReadFile("file.txt")
fmt.Println(string(data))
// Ignore data
_, err := os.ReadFile("file.txt")
if err != nil {
fmt.Println("Error:", err)
}
}
Returning Structs
Multiple Values as Struct
package main
import "fmt"
type Result struct {
Value int
Error error
}
func calculate(a, b int) Result {
if b == 0 {
return Result{
Value: 0,
Error: fmt.Errorf("division by zero"),
}
}
return Result{
Value: a / b,
Error: nil,
}
}
func main() {
result := calculate(10, 2)
if result.Error != nil {
fmt.Println("Error:", result.Error)
} else {
fmt.Println("Result:", result.Value)
}
}
Variadic Returns
Returning Slices
package main
import "fmt"
func getNumbers() []int {
return []int{1, 2, 3, 4, 5}
}
func main() {
nums := getNumbers()
fmt.Println(nums)
}
Best Practices
โ Good: Always Return Errors
// DO: Return errors explicitly
func process(data string) (string, error) {
if data == "" {
return "", fmt.Errorf("data cannot be empty")
}
return strings.ToUpper(data), nil
}
โ Bad: Ignore Errors
// DON'T: Ignore errors
func process(data string) string {
// No error handling
return strings.ToUpper(data)
}
โ Good: Use Named Returns for Clarity
// DO: Use named returns for clarity
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = fmt.Errorf("division by zero")
return
}
result = a / b
return
}
โ Good: Wrap Errors with Context
// DO: Wrap errors with context
if err != nil {
return fmt.Errorf("failed to process: %w", err)
}
โ Bad: Generic Error Messages
// DON'T: Use generic error messages
if err != nil {
return fmt.Errorf("error")
}
Summary
Multiple return values provide:
- Error handling without exceptions
- Multiple results without structs
- Named returns for clarity
- Idiomatic Go patterns
- Explicit error propagation
These features make Go’s error handling explicit and intentional.
Comments