JSTAcademy
0 XP
Dashboard
Crash Courses
Functions, Multiple Returns & Errors
30 min
Masters+170 XP
Crash Courses · Masters

Functions, Multiple Returns & Errors

First-class functions, named returns, and idiomatic error handling
30 min read+170 XP on completionCert: Go Crash Course
Tap any word in the text below to start reading from there.

Functions, Multiple Returns & Errors

Basic Functions

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

// Multiple params of same type can share type annotation
func multiply(a, b int) int {
    return a * b
}

Multiple Return Values

Go's killer feature for error handling — return both result and error:

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 main() {
    result, err := divide(10, 3)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Printf("Result: %.2f\n", result) // 3.33
}

The convention is always check err immediately after the call. Never ignore errors.

fmt.Errorf with Wrapping

func readUser(id int) (*User, error) {
    u, err := db.Find(id)
    if err != nil {
        return nil, fmt.Errorf("readUser %d: %w", id, err)
    }
    return u, nil
}

%w wraps the original error, allowing callers to use errors.Is and errors.As to inspect it.

Named Return Values

func minMax(nums []int) (min, max int) {
    min, max = nums[0], nums[0]
    for _, n := range nums {
        if n < min { min = n }
        if n > max { max = n }
    }
    return // "naked return" — returns named values
}

Use named returns sparingly — they're best for short functions where the names serve as documentation.

Variadic Functions

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

// Call with individual args or a slice
fmt.Println(sum(1, 2, 3))       // 6
nums := []int{4, 5, 6}
fmt.Println(sum(nums...))       // 15

defer

defer runs a call when the enclosing function exits — invaluable for cleanup:

func readFile(path string) error {
    f, err := os.Open(path)
    if err != nil {
        return err
    }
    defer f.Close() // guaranteed to run even if we return early

    // read from f ...
    return nil
}

Multiple defers run in LIFO order (last deferred, first executed).

First-Class Functions

Functions are values in Go:

apply := func(f func(int) int, x int) int {
    return f(x)
}

double := func(n int) int { return n * 2 }
fmt.Println(apply(double, 5)) // 10
0%