Skip to Content
Go Realm v1 is released 🎉
TopicsFunction

Functions in Go

Functions are first-class citizens in Go — they can be assigned to variables, passed as arguments, and returned from other functions.


1. Syntax Anatomy

// ↓ keyword ↓ name ↓ parameters ↓ return type func divide (a, b int) (int, error) { if b == 0 { return 0, fmt.Errorf("divide by zero") } return a / b, nil }
  • Parameters of the same type can share the type: a, b int
  • Multiple return values are wrapped in ()
  • error is always the last return value by convention

2. Return Styles

// Single return func square(x int) int { return x * x } // Multiple returns — idiomatic Go func divide(a, b int) (int, error) { if b == 0 { return 0, fmt.Errorf("divide by zero") } return a / b, nil } // Named returns — use sparingly, good for short functions 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 — returns min and max }

⚠️ Named returns + naked return hurt readability in long functions. Use only when it clearly adds documentation value.


3. First-Class Functions

// Assign to variable greet := func(name string) string { return "Hello, " + name } fmt.Println(greet("Go")) // Hello, Go // Pass as argument (higher-order function) func apply(x int, fn func(int) int) int { return fn(x) } fmt.Println(apply(5, func(n int) int { return n * 2 })) // 10 // Return a function (factory / closure) func multiplier(factor int) func(int) int { return func(x int) int { return x * factor } } double := multiplier(2) fmt.Println(double(7)) // 14

4. Closures ⭐

A closure is a function that captures variables from its surrounding scope. The captured variable is shared — not copied.

func counter() func() int { count := 0 return func() int { count++ // count lives on the heap — shared with the closure return count } } c := counter() fmt.Println(c()) // 1 fmt.Println(c()) // 2 fmt.Println(c()) // 3 c2 := counter() // independent counter fmt.Println(c2()) // 1

Production use: closures are used for middleware, callbacks, memoization, and functional options patterns.


5. Anonymous Functions & IIFE

// Anonymous function assigned to a variable square := func(x int) int { return x * x } fmt.Println(square(4)) // 16 // IIFE — declared and called immediately result := func(a, b int) int { return a + b }(10, 5) fmt.Println(result) // 15 // Common use: goroutine IIFE go func(msg string) { fmt.Println(msg) }("hello from goroutine")

6. defer in Functions

defer schedules a function call to run when the surrounding function returns — regardless of how it returns (normal, error, panic).

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

Defer rules:

  • Arguments are evaluated immediately, not at run time
  • Multiple defers run in LIFO order
  • Deferred functions can read/modify named return values
// Defers run LIFO defer fmt.Println("third") defer fmt.Println("second") defer fmt.Println("first") // Output: first → second → third

7. init() Function

func init() { // runs automatically before main() // no parameters, no return value }
PropertyDetail
Runs beforemain()
Parameters / returnsNone
Per fileMultiple init() allowed
OrderFile order within package; import dependency order across packages
Use forRegistering drivers, loading config, validating flags
AvoidBusiness logic, side effects that are hard to test
var db *sql.DB func init() { var err error db, err = sql.Open("postgres", os.Getenv("DB_URL")) if err != nil { log.Fatal(err) } }

8. Recursion

func factorial(n int) int { if n == 0 { return 1 } return n * factorial(n-1) } // With memoization (production pattern) var memo = map[int]int{} func fib(n int) int { if n <= 1 { return n } if v, ok := memo[n]; ok { return v } memo[n] = fib(n-1) + fib(n-2) return memo[n] }

9. Function Types & Type Aliases

// Define a function type type Transformer func(int) int func applyAll(nums []int, fns ...Transformer) []int { result := make([]int, len(nums)) copy(result, nums) for _, fn := range fns { for i, v := range result { result[i] = fn(v) } } return result } double := Transformer(func(x int) int { return x * 2 }) addOne := Transformer(func(x int) int { return x + 1 }) fmt.Println(applyAll([]int{1, 2, 3}, double, addOne)) // [3 5 7]

10. Common Mistakes ⚠️

MistakeProblemFix
Ignoring error returnsilent failuresalways check err != nil
Naked return in long functionhard to readuse explicit returns
Closure capturing loop var (pre-1.22)all closures see same valueshadow: v := v or use Go 1.22+
defer argument captured latewrong value deferredargs evaluated at defer statement, not at call
Calling init() manuallyundefined behaviourinit is called by runtime only
Huge function doing everythinguntestablebreak into small, single-purpose functions

11. Interview Cheat Sheet

Q: What makes Go functions first-class?

They can be assigned to variables, passed as arguments, and returned from other functions — just like any other value.

Q: What is a closure?

A function that captures and shares variables from its enclosing scope. The captured variable lives on the heap and is shared between the closure and the outer scope.

Q: When are defer arguments evaluated?

Immediately when the defer statement is reached — not when the deferred function actually executes. Only the function call is delayed.

Q: What is the difference between anonymous function and closure?

All closures are anonymous functions, but not all anonymous functions are closures. A closure specifically captures at least one variable from the outer scope.

Q: What is init() and when does it run?

A special no-arg, no-return function that runs automatically before main(). Multiple init() functions per file/package are allowed. Used for setup like registering drivers or validating env vars.

Q: Should you use named return values?

Only for short functions where they act as documentation. In long functions, naked return statements make code hard to follow and should be avoided.