Learn Go
beginner1 min read

Functions

Functions are the primary unit of code reuse in Go. Go functions are first-class values — they can be assigned to variables, passed as arguments, and returned from other functions.

Declaring a Function

The basic syntax is func name(params) returnType { body }:

package main
 
import "fmt"
 
func add(a int, b int) int {
    return a + b
}
 
func main() {
    result := add(3, 4)
    fmt.Println(result) // 7
}

When consecutive parameters share a type, you can group them:

package main
 
import "fmt"
 
func multiply(a, b int) int {
    return a * b
}
 
func main() {
    fmt.Println(multiply(6, 7)) // 42
}

Multiple Return Values

Go functions can return more than one value. The idiomatic pattern returns a result alongside an 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("%.4f\n", result) // 3.3333
}

Idiomatic Go: Always check errors. The convention result, err := f() followed by if err != nil appears throughout the standard library and idiomatic Go code.

Named Return Values

You can name the return values in the function signature. Named returns act like local variables and can be returned with a bare return:

package main
 
import "fmt"
 
func minMax(nums []int) (min, max int) {
    min, max = nums[0], nums[0]
    for _, n := range nums[1:] {
        if n < min {
            min = n
        }
        if n > max {
            max = n
        }
    }
    return // naked return
}
 
func main() {
    lo, hi := minMax([]int{3, 1, 4, 1, 5, 9, 2, 6})
    fmt.Println(lo, hi) // 1 9
}

Use named returns sparingly — they are most useful when the function body is short and the names add clarity to the signature.

Variadic Functions

A variadic function accepts a variable number of arguments. The final parameter uses the ... prefix:

package main
 
import "fmt"
 
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}
 
func main() {
    fmt.Println(sum(1, 2, 3))       // 6
    fmt.Println(sum(10, 20, 30, 40)) // 100
 
    nums := []int{5, 6, 7}
    fmt.Println(sum(nums...)) // 18 — spread a slice with ...
}

Functions as Values

Functions are first-class citizens in Go:

package main
 
import "fmt"
 
func apply(nums []int, fn func(int) int) []int {
    result := make([]int, len(nums))
    for i, n := range nums {
        result[i] = fn(n)
    }
    return result
}
 
func main() {
    double := func(n int) int { return n * 2 }
    fmt.Println(apply([]int{1, 2, 3, 4}, double)) // [2 4 6 8]
}

Key Takeaways