Functions
Function basics
Section titled “Function basics”A Go function declares its parameter types and return types explicitly. The return type appears after the parameter list:
func add(a int, b int) int { return a + b}
// Consecutive parameters of the same type can share a type annotationfunc add(a, b int) int { return a + b}Multiple return values
Section titled “Multiple return values”Go functions can return more than one value. The idiomatic pattern is (result, error) — the caller must handle or explicitly discard the error:
func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil}
result, err := divide(10, 3)if err != nil { log.Fatal(err)}fmt.Println(result)Named return values
Section titled “Named return values”Return values can be named. Named returns pre-declare variables and allow a bare return (a return with no arguments that returns the current values of the named variables). Use them sparingly — they are clearest in short functions where the names genuinely document the result:
func minMax(nums []int) (min, max int) { min, max = nums[0], nums[0] for _, v := range nums[1:] { if v < min { min = v } if v > max { max = v } } return // bare return: returns current min, max}Variadic functions
Section titled “Variadic functions”A variadic function accepts a variable number of arguments of the same type. Declare the last parameter with ...:
func sum(nums ...int) int { total := 0 for _, n := range nums { total += n } return total}
sum(1, 2, 3) // individual argssum([]int{1,2,3}...) // spread a slice with ...Inside the function, nums is a []int slice.
defer schedules a function call to run when the surrounding function returns, regardless of which return path is taken. It is the idiomatic way to clean up resources:
func readFile(name string) error { f, err := os.Open(name) if err != nil { return err } defer f.Close() // runs when readFile returns
// ... work with f ... return nil}Multiple deferred calls execute in LIFO order (last deferred, first to run). Arguments to the deferred function are evaluated immediately at the defer statement, not when the call runs.
Closures and first-class functions
Section titled “Closures and first-class functions”Functions are first-class values in Go. You can assign them to variables, pass them as arguments, and return them from other functions:
double := func(n int) int { return n * 2 }fmt.Println(double(5)) // 10A closure is a function that captures variables from its enclosing scope. The captured variable is shared — the closure sees mutations to it:
func counter() func() int { n := 0 return func() int { n++ return n }}
c := counter()fmt.Println(c()) // 1fmt.Println(c()) // 2fmt.Println(c()) // 3Each call to counter() creates an independent n, so two counters do not interfere with each other.
package main
import ( "errors" "fmt")
// Multiple return valuesfunc divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil}
// Variadicfunc sum(nums ...int) int { total := 0 for _, n := range nums { total += n } return total}
// Closurefunc counter() func() int { n := 0 return func() int { n++ return n }}
// defer demofunc deferDemo() { fmt.Println("deferDemo start") defer fmt.Println("deferred 1 (runs last)") defer fmt.Println("deferred 2 (runs second)") defer fmt.Println("deferred 3 (runs first)") fmt.Println("deferDemo end")}
func main() { // Multiple returns result, err := divide(10, 3) if err != nil { fmt.Println("error:", err) } else { fmt.Printf("10 / 3 = %.4f\n", result) }
_, err = divide(5, 0) if err != nil { fmt.Println("divide by zero:", err) }
// Variadic fmt.Println("sum(1..5) =", sum(1, 2, 3, 4, 5))
// Closure counter c := counter() fmt.Println("counter:", c(), c(), c())
// defer LIFO deferDemo()}Loading Go runtime (first run only, ~8 MB)…