Multiple return values are how Go reports errors, and closures appear in callbacks, sorting and goroutines.
A function lists parameter names before types: func add(a, b int) int. Consecutive parameters of the same type can share it.
Go functions can return multiple values. The universal convention is a result plus an error: func parse(s string) (int, error). The caller unpacks both, n, err := parse(s), and uses _ to discard one it doesn't need. Results can also be named, func split(sum int) (x, y int); named results start at their zero values and a bare return returns them. Use names for documentation, but avoid bare returns in long functions — they hurt readability.
A variadic parameter, func sum(nums ...int), receives a slice. Call it with separate arguments, sum(1, 2, 3), or spread an existing slice with sum(xs...).
Arguments are always passed by value: the function gets a copy. (Slices, maps and pointers are small values that refer to shared data, which is why modifying a slice's elements is visible to the caller.)
Functions are first-class values. You can store them in variables, pass them as arguments (sort.Slice(xs, func(i, j int) bool {...})) and return them. A function literal that refers to variables of the enclosing function is a closure: it captures those variables themselves, not copies, so changes are shared and the variables live as long as the closure does.
Go has no default parameter values and no overloading; use distinct names or an options struct instead.
Example
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func counter() func() int {
n := 0
return func() int { n++; return n } // closure captures n
}
func main() {
if q, err := divide(1, 0); err != nil {
fmt.Println("error:", err) // error: division by zero
} else {
fmt.Println(q)
}
next := counter()
next()
fmt.Println(next()) // 2
}Remember
- Return
(result, error)and check the error at the call site - Variadic
...Tarrives as a slice; spread a slice withxs... - Closures capture variables by reference, not by value
Watch out for
- Ignoring a returned error by assigning it to
_without a good reason.