Functions#
Functions in Go are first-class values: they can be stored, passed, returned, and assigned to interface methods. Signatures support multiple return values, named returns, variadic parameters, generic type parameters, and pointer-or-value method receivers.
/oop`. For
goroutines launched with go, see Concurrency.
Declaration#
func add(a, b int) int {
return a + b
}
// multiple return values
func divmod(a, b int) (int, int) {
return a / b, a % b
}
// named returns
func parsePort(s string) (port int, err error) {
port, err = strconv.Atoi(s)
if err != nil { return } // naked return uses named values
if port < 1 || port > 65535 {
err = fmt.Errorf("bad port: %d", port)
}
return
}
Use named returns sparingly; they read well for short functions, become noise in long ones.
Parameters#
Parameters of the same type share a single type annotation.
func max(a, b, c int) int { /* … */ return 0 }
Variadic parameters use ...T; the callee sees the
arguments as a []T.
func sum(xs ...int) int {
total := 0
for _, x := range xs { total += x }
return total
}
sum(1, 2, 3)
sum([]int{1, 2, 3}...) // spread a slice
Multiple returns#
The standard return form is (value, error). The operator
checks err != nil and returns it (often wrapped) on the
unhappy path.
func load(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("load %q: %w", path, err)
}
return data, nil
}
The blank identifier _ discards a return value.
_, err := os.Stat(path)
Closures#
A function literal captures the surrounding locals by reference.
func makeCounter() func() int {
n := 0
return func() int {
n++
return n
}
}
next := makeCounter()
fmt.Println(next(), next(), next()) // 1 2 3
Closures over loop variables are now safe per-iteration as of Go 1.22; in older versions the operator copied the variable into a fresh scope inside the loop.
defer#
defer is part of the function surface; see Control flow
for the runtime semantics. The operator pairs every resource
acquisition with an immediate defer to its release.
func process(path string) error {
f, err := os.Open(path)
if err != nil { return err }
defer f.Close()
// …
return nil
}
Generics#
Type parameters in square brackets.
func Head[T any](xs []T) (T, bool) {
var zero T
if len(xs) == 0 { return zero, false }
return xs[0], true
}
n, ok := Head([]int{1, 2, 3})
Constraints describe what the type parameter supports;
cmp.Ordered covers all orderable primitives, comparable
covers anything usable as a map key.
func Max[T cmp.Ordered](a, b T) T {
if a > b { return a }
return b
}
type Numeric interface { ~int | ~int64 | ~float64 }
func Sum[T Numeric](xs []T) T {
var total T
for _, x := range xs { total += x }
return total
}
The ~ prefix means “or any type with this underlying type”
(so type Counter int matches ~int).
Method functions#
A method is a function with a receiver. The receiver appears in parentheses before the function name; pointer receivers allow the method to mutate the value.
type Counter struct{ n int }
func (c Counter) Get() int { return c.n }
func (c *Counter) Inc() { c.n++ }
var c Counter
c.Inc() // Go takes &c implicitly
fmt.Println(c.Get()) // 1
The full surface (method sets, embedding, interface satisfaction) lives in OOP.
Function types as parameters#
Pass behaviour as a parameter; this is how the operator parameterises iteration and filtering.
type Predicate[T any] func(T) bool
func Filter[T any](xs []T, p Predicate[T]) []T {
out := xs[:0]
for _, x := range xs {
if p(x) { out = append(out, x) }
}
return out
}
adults := Filter(users, func(u User) bool { return u.Age >= 18 })
init#
func init() {} runs once per package at program startup,
after package-level variable initialisation. Multiple init
functions per file are allowed; the order across files is
governed by lexicographic filename order.
var logger *slog.Logger
func init() {
logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
}
Avoid init for anything beyond setting package-private
state; long-running setup belongs in an explicit constructor
the application calls.
References#
Syntax for the lexical surface
funclives in.Types for
error, function types, generics.OOP for methods, interfaces, embedding.
Concurrency for
goanddeferinteraction.Errors for the
errorvalue convention.