Go functions support multiple return values, closures, variadic arguments, and named returns. They are first-class values — you can pass them as arguments and store them in variables.
Multiple Return Values
This is Go's most distinctive function feature:
Go
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
result, err := divide(10, 3)
if err != nil {
log.Fatal(err)
}
fmt.Println(result) // 3.333...Convention: the last return value is always the error.
Named Return Values
Go
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // bare return — returns x and y
}Named returns are rarely used in modern Go — prefer explicit returns.
Variadic Functions
Accept any number of arguments:
Go
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
sum(1, 2, 3) // 6
sum(1, 2, 3, 4) // 10
// Pass a slice
nums := []int{1, 2, 3}
sum(nums...) // 6Functions as Values
Go
// Assign to a variable
add := func(a, b int) int {
return a + b
}
fmt.Println(add(3, 4)) // 7
// Pass as an argument
numbers := []int{1, 2, 3, 4, 5}
evens := filter(numbers, func(n int) bool {
return n%2 == 0
})Defer
defer runs when the surrounding function returns — perfect for
cleanup:
Go
func readFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // guaranteed to run, even if an error occurs
// ... read from f
return nil
}Stacking defers execute in LIFO order (last deferred, first executed):
Go
fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
// Output: 1, 3, 2Closures
Functions that capture variables from their surrounding scope:
Go
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
c := counter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2
fmt.Println(c()) // 3Tips
- Check errors at every call site —
if err != nil. - Use
deferfor cleanup (closing files, releasing locks). - Use closures for stateful functions (counters, generators).
- Keep functions short — if it does one thing well, it is a good function.
Next: interfaces — Go's secret weapon.