Lesson 6 of 30 beginner 4 min read

Before this:Values, variables & types

Functions & error handling

Key takeaways Go functions can return multiple values, and the idiom is to return a result plus an error. There are no exceptions: a function that can fail hands back an error that is nil on success, and the caller checks it with if err != nil. This makes every failure path visible in the code.

Functions are where Go’s philosophy shows most clearly. This lesson covers how you write them and the error-handling style that pervades every Go program you’ll ever read.

Writing a function

func channelWidth(highHz, lowHz float64) float64 {
    return highHz - lowHz
}

Parameters come with their types; the return type comes after the parentheses. When consecutive parameters share a type you can write it once (highHz, lowHz float64).

Multiple return values

A Go function can return several values at once — used constantly to return “the answer, and whether it worked”:

func tune(freqHz float64) (float64, error) {
    if freqHz <= 0 {
        return 0, fmt.Errorf("invalid frequency: %v", freqHz)
    }
    return freqHz, nil
}

The second return value is an error. On success it is nil; on failure it carries a message.

The error pattern

Because errors are just values, the caller handles them immediately:

freq, err := tune(-5)
if err != nil {
    return err        // pass the problem up to whoever called us
}
// safe to use freq here — we know tune succeeded

You will see if err != nil on a huge fraction of Go lines. It can feel repetitive, but it means the error paths are right there in front of you — nothing is hidden in an invisible exception jumping up the stack.

tune(freq) result, err err == nil -> use result err != nil -> handle it
Every fallible call forks the same way: success uses the result; failure handles the error.

defer: cleanup that always runs

defer schedules a call to run when the surrounding function returns, no matter how it returns. It’s the standard way to release resources:

f, err := os.Open("capture.cfile")
if err != nil {
    return err
}
defer f.Close()   // runs when this function exits, success or error

This keeps “open” and “close” next to each other and guarantees the file is closed even on an early error return.

Quick check: a function returns (value, error). What does an error of nil mean?

Recap

  • Go functions declare parameter and return types and can return multiple values.
  • Fallible functions return an error; it is nil on success.
  • The if err != nil idiom handles failures explicitly — Go has no exceptions.
  • defer guarantees cleanup runs when a function returns.

Next up: bundling data together with structs and giving it behaviour with methods.

Frequently asked questions

Why doesn't Go have exceptions?

Go’s designers felt exceptions hide the error paths and make control flow hard to follow. Instead, a function that can fail returns an error value alongside its result, and the caller decides what to do right there. The code is more explicit — you can see every place an error is handled — at the cost of a little more typing.

What does if err != nil mean?

It’s the standard Go idiom for checking whether the function you just called failed. Functions return an error that is nil on success and non-nil on failure, so if err != nil { ... } means “if something went wrong, handle it here” — usually by returning the error up to the caller or logging it.