# Functions

> Source: https://learn-go.org/functions/
> Part of Learn Go, free to read.

```go
func add(a int, b int) int {
    return a + b
}

func addSub(a, b int) (int, int) {   // same type? declare it once
    return a + b, a - b
}
```

## Multiple return values

This is the feature that defines Go's style. Almost every function that can fail returns two values, and the second is an `error`.

```go
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("divide %v by zero", a)
    }
    return a / b, nil
}

result, err := divide(10, 2)
if err != nil {
    return fmt.Errorf("compute ratio: %w", err)
}
```

Three conventions worth learning immediately:

- The error is always the **last** return value.
- On error, other return values are their zero value and must not be used.
- `%w` in `fmt.Errorf` wraps the error so `errors.Is` and `errors.As` can find it later. `%v` does not — that difference is invisible in the message and breaks callers.

## Named return values

```go
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return                 // "naked" return — returns x and y
}
```

Useful for documenting what each value means, and useful with `defer` for modifying a result on the way out. Avoid naked returns in anything longer than a few lines: the reader has to scroll to find what is actually returned.

## Variadic functions

```go
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

sum(1, 2, 3)
sum(values...)             // spread a slice
```

## Functions are values

```go
func apply(nums []int, f func(int) int) []int {
    out := make([]int, len(nums))
    for i, n := range nums {
        out[i] = f(n)
    }
    return out
}

doubled := apply([]int{1, 2, 3}, func(n int) int { return n * 2 })
```

## Closures

```go
func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

next := counter()
next()   // 1
next()   // 2
```

Each call to `counter` gets its own `count`.

## defer

`defer` schedules a call to run when the surrounding function returns — including when it returns because of a panic.

```go
func readConfig(path string) ([]byte, error) {
    f, err := os.Open(path)
    if err != nil {
        return nil, fmt.Errorf("open %s: %w", path, err)
    }
    defer f.Close()          // runs no matter which return we take
    return io.ReadAll(f)
}
```

Deferred calls run last-in-first-out, and their arguments are evaluated immediately — at the `defer` line, not when it runs. That trips people up exactly once.

:::warn Closing a writable file
`defer f.Close()` silently discards the close error. For a file you wrote to, that error is how you find out the write failed. Capture it with a named return:

```go
func write(path string, data []byte) (err error) {
    f, err := os.Create(path)
    if err != nil { return err }
    defer func() {
        if cerr := f.Close(); cerr != nil && err == nil {
            err = cerr
        }
    }()
    _, err = f.Write(data)
    return err
}
```
:::

## Common questions

### Why does Go not have default parameter values?

Deliberate simplicity: there is one calling convention and no overload resolution to reason about. The idiomatic replacements are a config struct, or functional options (`WithTimeout(5*time.Second)`) when a package needs many optional settings.

### When should I use named return values?

When the names document something the types do not — `(width, height int)` — or when you need `defer` to modify the result, as in the close example above. Otherwise prefer explicit returns.

### Is `defer` expensive?

Not meaningfully since Go 1.14; it is close to free in the common case. Use it. The one place to think about it is a `defer` inside a hot loop, where it accumulates until the function returns rather than the loop iteration.
